Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
las3_pub
/
predictable_parallel_patterns
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
7796022f
authored
Jan 30, 2020
by
FritzFlorian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix matrix multiplication benchmark for new scheduler.
parent
01596ff3
Pipeline
#1393
failed with stages
in 26 seconds
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
672 additions
and
688 deletions
+672
-688
app/benchmark_matrix/main.cpp
+22
-40
lib/pls/include/pls/algorithms/for_each.h
+14
-16
lib/pls/include/pls/algorithms/for_each_impl.h
+28
-24
lib/pls/include/pls/internal/helpers/range.h
+608
-608
No files found.
app/benchmark_matrix/main.cpp
View file @
7796022f
#include "pls/internal/scheduling/scheduler.h"
#include "pls/internal/scheduling/scheduler.h"
#include "pls/internal/scheduling/parallel_result.h"
#include "pls/internal/scheduling/static_scheduler_memory.h"
#include "pls/internal/scheduling/scheduler_memory.h"
#include "pls/algorithms/for_each.h"
#include "pls/algorithms/for_each.h"
using
namespace
pls
::
internal
::
scheduling
;
using
namespace
pls
::
internal
::
scheduling
;
...
@@ -15,17 +14,20 @@ class pls_matrix : public matrix::matrix<T, SIZE> {
...
@@ -15,17 +14,20 @@ class pls_matrix : public matrix::matrix<T, SIZE> {
public
:
public
:
pls_matrix
()
:
matrix
::
matrix
<
T
,
SIZE
>
()
{}
pls_matrix
()
:
matrix
::
matrix
<
T
,
SIZE
>
()
{}
parallel_result
<
int
>
pls_multiply
(
const
matrix
::
matrix
<
T
,
SIZE
>
&
a
,
const
matrix
::
matrix
<
T
,
SIZE
>
&
b
)
{
void
pls_multiply
(
const
matrix
::
matrix
<
T
,
SIZE
>
&
a
,
const
matrix
::
matrix
<
T
,
SIZE
>
&
b
)
{
return
pls
::
algorithm
::
for_each_range
(
0
,
SIZE
,
[
this
,
&
a
,
&
b
](
int
i
)
{
pls
::
algorithm
::
for_each_range
(
0
,
SIZE
,
[
this
,
&
a
,
&
b
](
int
i
)
{
this
->
multiply_column
(
i
,
a
,
b
);
this
->
multiply_column
(
i
,
a
,
b
);
});
});
}
}
};
};
constexpr
size_t
MAX_NUM_THREADS
=
8
;
constexpr
int
MAX_NUM_THREADS
=
8
;
constexpr
size_t
MAX_NUM_TASKS
=
32
;
constexpr
int
MAX_NUM_TASKS
=
32
;
constexpr
size_t
MAX_NUM_CONTS
=
32
;
constexpr
int
MAX_STACK_SIZE
=
1024
*
1
;
constexpr
size_t
MAX_CONT_SIZE
=
512
;
static_scheduler_memory
<
MAX_NUM_THREADS
,
MAX_NUM_TASKS
,
MAX_STACK_SIZE
>
global_scheduler_memory
;
int
main
(
int
argc
,
char
**
argv
)
{
int
main
(
int
argc
,
char
**
argv
)
{
int
num_threads
;
int
num_threads
;
...
@@ -40,40 +42,20 @@ int main(int argc, char **argv) {
...
@@ -40,40 +42,20 @@ int main(int argc, char **argv) {
pls_matrix
<
double
,
matrix
::
MATRIX_SIZE
>
b
;
pls_matrix
<
double
,
matrix
::
MATRIX_SIZE
>
b
;
pls_matrix
<
double
,
matrix
::
MATRIX_SIZE
>
result
;
pls_matrix
<
double
,
matrix
::
MATRIX_SIZE
>
result
;
static_scheduler_memory
<
MAX_NUM_THREADS
,
scheduler
scheduler
{
global_scheduler_memory
,
(
unsigned
)
num_threads
};
MAX_NUM_TASKS
,
MAX_NUM_CONTS
,
MAX_CONT_SIZE
>
static_scheduler_memory
;
scheduler
scheduler
{
static_scheduler_memory
,
(
unsigned
int
)
num_threads
};
for
(
int
i
=
0
;
i
<
matrix
::
WARMUP_ITERATIONS
;
i
++
)
{
scheduler
.
perform_work
([
&
]()
{
scheduler
.
perform_work
([
&
]()
{
return
scheduler
::
par
([
&
]()
{
for
(
int
i
=
0
;
i
<
matrix
::
WARMUP_ITERATIONS
;
i
++
)
{
return
result
.
pls_multiply
(
a
,
b
);
result
.
pls_multiply
(
a
,
b
);
},
[]()
{
}
return
parallel_result
<
int
>
{
0
};
});
}).
then
([
&
](
int
,
int
)
{
return
parallel_result
<
int
>
{
0
};
});
});
}
for
(
int
i
=
0
;
i
<
matrix
::
NUM_ITERATIONS
;
i
++
)
{
scheduler
.
perform_work
([
&
](
)
{
scheduler
.
perform_work
([
&
](
)
{
for
(
int
i
=
0
;
i
<
matrix
::
NUM_ITERATIONS
;
i
++
)
{
runner
.
start_iteration
();
runner
.
start_iteration
();
result
.
pls_multiply
(
a
,
b
);
return
scheduler
::
par
([
&
]()
{
runner
.
end_iteration
();
return
result
.
pls_multiply
(
a
,
b
);
}
},
[]()
{
});
return
parallel_result
<
int
>
{
0
};
}).
then
([
&
](
int
,
int
)
{
runner
.
end_iteration
();
return
parallel_result
<
int
>
{
0
};
});
});
}
runner
.
commit_results
(
true
);
runner
.
commit_results
(
true
);
}
}
lib/pls/include/pls/algorithms/for_each.h
View file @
7796022f
...
@@ -2,8 +2,6 @@
...
@@ -2,8 +2,6 @@
#ifndef PLS_PARALLEL_FOR_H
#ifndef PLS_PARALLEL_FOR_H
#define PLS_PARALLEL_FOR_H
#define PLS_PARALLEL_FOR_H
#include "pls/internal/scheduling/parallel_result.h"
namespace
pls
{
namespace
pls
{
namespace
algorithm
{
namespace
algorithm
{
...
@@ -11,26 +9,26 @@ class fixed_strategy;
...
@@ -11,26 +9,26 @@ class fixed_strategy;
class
dynamic_strategy
;
class
dynamic_strategy
;
template
<
typename
Function
,
typename
ExecutionStrategy
>
template
<
typename
Function
,
typename
ExecutionStrategy
>
pls
::
internal
::
scheduling
::
parallel_result
<
int
>
for_each_range
(
unsigned
long
first
,
void
for_each_range
(
unsigned
long
first
,
unsigned
long
last
,
unsigned
long
last
,
const
Function
&
function
,
const
Function
&
function
,
ExecutionStrategy
&
execution_strategy
);
ExecutionStrategy
&
execution_strategy
);
template
<
typename
Function
>
template
<
typename
Function
>
pls
::
internal
::
scheduling
::
parallel_result
<
int
>
for_each_range
(
unsigned
long
first
,
void
for_each_range
(
unsigned
long
first
,
unsigned
long
last
,
unsigned
long
last
,
const
Function
&
function
);
const
Function
&
function
);
template
<
typename
RandomIt
,
typename
Function
,
typename
ExecutionStrategy
>
template
<
typename
RandomIt
,
typename
Function
,
typename
ExecutionStrategy
>
pls
::
internal
::
scheduling
::
parallel_result
<
int
>
for_each
(
RandomIt
first
,
void
for_each
(
RandomIt
first
,
RandomIt
last
,
RandomIt
last
,
const
Function
&
function
,
const
Function
&
function
,
ExecutionStrategy
execution_strategy
);
ExecutionStrategy
execution_strategy
);
template
<
typename
RandomIt
,
typename
Function
>
template
<
typename
RandomIt
,
typename
Function
>
pls
::
internal
::
scheduling
::
parallel_result
<
int
>
for_each
(
RandomIt
first
,
void
for_each
(
RandomIt
first
,
RandomIt
last
,
RandomIt
last
,
const
Function
&
function
);
const
Function
&
function
);
}
}
}
}
...
...
lib/pls/include/pls/algorithms/for_each_impl.h
View file @
7796022f
...
@@ -11,10 +11,10 @@ namespace algorithm {
...
@@ -11,10 +11,10 @@ namespace algorithm {
namespace
internal
{
namespace
internal
{
template
<
typename
RandomIt
,
typename
Function
>
template
<
typename
RandomIt
,
typename
Function
>
pls
::
internal
::
scheduling
::
parallel_result
<
int
>
for_each
(
const
RandomIt
first
,
void
for_each
(
const
RandomIt
first
,
const
RandomIt
last
,
const
RandomIt
last
,
const
Function
function
,
const
Function
function
,
const
long
min_elements
)
{
const
long
min_elements
)
{
using
namespace
::
pls
::
internal
::
scheduling
;
using
namespace
::
pls
::
internal
::
scheduling
;
const
long
num_elements
=
std
::
distance
(
first
,
last
);
const
long
num_elements
=
std
::
distance
(
first
,
last
);
...
@@ -23,25 +23,23 @@ pls::internal::scheduling::parallel_result<int> for_each(const RandomIt first,
...
@@ -23,25 +23,23 @@ pls::internal::scheduling::parallel_result<int> for_each(const RandomIt first,
for
(
auto
current
=
first
;
current
!=
last
;
current
++
)
{
for
(
auto
current
=
first
;
current
!=
last
;
current
++
)
{
function
(
*
current
);
function
(
*
current
);
}
}
return
parallel_result
<
int
>
{
0
};
}
else
{
}
else
{
// Cut in half recursively
// Cut in half recursively
const
long
middle_index
=
num_elements
/
2
;
const
long
middle_index
=
num_elements
/
2
;
return
scheduler
::
par
([
first
,
middle_index
,
last
,
function
,
min_elements
]
{
scheduler
::
spawn
([
first
,
middle_index
,
last
,
&
function
,
min_elements
]
{
return
internal
::
for_each
(
first
,
return
internal
::
for_each
(
first
,
first
+
middle_index
,
first
+
middle_index
,
function
,
function
,
min_elements
);
min_elements
);
},
[
first
,
middle_index
,
last
,
function
,
min_elements
]
{
});
scheduler
::
spawn
([
first
,
middle_index
,
last
,
&
function
,
min_elements
]
{
return
internal
::
for_each
(
first
+
middle_index
,
return
internal
::
for_each
(
first
+
middle_index
,
last
,
last
,
function
,
function
,
min_elements
);
min_elements
);
}).
then
([](
int
,
int
)
{
return
parallel_result
<
int
>
{
0
};
});
});
scheduler
::
sync
();
}
}
}
}
...
@@ -52,7 +50,7 @@ class dynamic_strategy {
...
@@ -52,7 +50,7 @@ class dynamic_strategy {
explicit
dynamic_strategy
(
const
unsigned
int
tasks_per_thread
=
4
)
:
tasks_per_thread_
{
tasks_per_thread
}
{};
explicit
dynamic_strategy
(
const
unsigned
int
tasks_per_thread
=
4
)
:
tasks_per_thread_
{
tasks_per_thread
}
{};
long
calculate_min_elements
(
long
num_elements
)
const
{
long
calculate_min_elements
(
long
num_elements
)
const
{
const
long
num_threads
=
pls
::
internal
::
scheduling
::
thread_state
::
get
().
scheduler_
->
num_threads
();
const
long
num_threads
=
pls
::
internal
::
scheduling
::
thread_state
::
get
().
get_scheduler
().
num_threads
();
return
num_elements
/
(
num_threads
*
tasks_per_thread_
);
return
num_elements
/
(
num_threads
*
tasks_per_thread_
);
}
}
private
:
private
:
...
@@ -71,32 +69,38 @@ class fixed_strategy {
...
@@ -71,32 +69,38 @@ class fixed_strategy {
};
};
template
<
typename
RandomIt
,
typename
Function
,
typename
ExecutionStrategy
>
template
<
typename
RandomIt
,
typename
Function
,
typename
ExecutionStrategy
>
pls
::
internal
::
scheduling
::
parallel_result
<
int
>
for_each
(
RandomIt
first
,
void
for_each
(
RandomIt
RandomIt
last
,
first
,
const
Function
&
function
,
RandomIt
last
,
ExecutionStrategy
execution_strategy
)
{
const
Function
&
function
,
ExecutionStrategy
execution_strategy
)
{
long
num_elements
=
std
::
distance
(
first
,
last
);
long
num_elements
=
std
::
distance
(
first
,
last
);
return
internal
::
for_each
(
first
,
last
,
function
,
execution_strategy
.
calculate_min_elements
(
num_elements
));
return
internal
::
for_each
(
first
,
last
,
function
,
execution_strategy
.
calculate_min_elements
(
num_elements
)
);
}
}
template
<
typename
RandomIt
,
typename
Function
>
template
<
typename
RandomIt
,
typename
Function
>
pls
::
internal
::
scheduling
::
parallel_result
<
int
>
for_each
(
RandomIt
first
,
RandomIt
last
,
const
Function
&
function
)
{
void
for_each
(
RandomIt
first
,
RandomIt
last
,
const
Function
&
function
)
{
return
for_each
(
first
,
last
,
function
,
dynamic_strategy
{
4
});
return
for_each
(
first
,
last
,
function
,
dynamic_strategy
{
4
});
}
}
template
<
typename
Function
,
typename
ExecutionStrategy
>
template
<
typename
Function
,
typename
ExecutionStrategy
>
pls
::
internal
::
scheduling
::
parallel_result
<
int
>
for_each_range
(
unsigned
long
first
,
void
for_each_range
(
unsigned
long
first
,
unsigned
long
last
,
unsigned
long
last
,
const
Function
&
function
,
const
Function
&
function
,
ExecutionStrategy
execution_strategy
)
{
ExecutionStrategy
execution_strategy
)
{
auto
range
=
pls
::
internal
::
helpers
::
range
(
first
,
last
);
auto
range
=
pls
::
internal
::
helpers
::
range
(
first
,
last
);
return
for_each
(
range
.
begin
(),
range
.
end
(),
function
,
execution_strategy
);
return
for_each
(
range
.
begin
(),
range
.
end
(),
function
,
execution_strategy
);
}
}
template
<
typename
Function
>
template
<
typename
Function
>
pls
::
internal
::
scheduling
::
parallel_result
<
int
>
for_each_range
(
unsigned
long
first
,
void
for_each_range
(
unsigned
long
first
,
unsigned
long
last
,
unsigned
long
last
,
const
Function
&
function
)
{
const
Function
&
function
)
{
auto
range
=
pls
::
internal
::
helpers
::
range
(
first
,
last
);
auto
range
=
pls
::
internal
::
helpers
::
range
(
first
,
last
);
return
for_each
(
range
.
begin
(),
range
.
end
(),
function
);
return
for_each
(
range
.
begin
(),
range
.
end
(),
function
);
}
}
...
...
lib/pls/include/pls/internal/helpers/range.h
View file @
7796022f
/*
/*
Range
Range
=====
=====
Copyright (c) 2009-2011 Khaled Alshaya
Copyright (c) 2009-2011 Khaled Alshaya
Distributed under the Boost Software License, version 1.0
Distributed under the Boost Software License, version 1.0
(See the license at: http://www.boost.org/license_1_0.txt).
(See the license at: http://www.boost.org/license_1_0.txt).
*/
*/
/*
/*
Rationale
Rationale
=========
=========
In Python, there is a beautiful function called "range".
In Python, there is a beautiful function called "range".
"range" allows the programmer to iterate over a range elegantly.
"range" allows the programmer to iterate over a range elegantly.
This concept is not as general as "for-loops" in C++,
This concept is not as general as "for-loops" in C++,
but non the less, it expresses the intent of the programmer
but non the less, it expresses the intent of the programmer
clearer than the general "for-loops" in many cases.
clearer than the general "for-loops" in many cases.
Design
Design
======
======
Range is made to be STL-like library. In fact, it is
Range is made to be STL-like library. In fact, it is
built on top of the concepts of STL. The library is designed to
built on top of the concepts of STL. The library is designed to
work with STL algorithms as well. Range is more flexible
work with STL algorithms as well. Range is more flexible
than the Python "range", because:
than the Python "range", because:
Range is an "immutable ordered random access container"
Range is an "immutable ordered random access container"
Specifications
Specifications
==============
==============
Range satisfies the following requirements:
Range satisfies the following requirements:
* Immutable.
* Immutable.
* Random Access Container.
* Random Access Container.
* Random Access Iterator Interface.
* Random Access Iterator Interface.
* Constant Time Complexity Operations.
* Constant Time Complexity Operations.
Range models an ordered sequence of elements,
Range models an ordered sequence of elements,
where a range is defined by:
where a range is defined by:
[begin, end)
[begin, end)
* begin: the first element in the range. (Inclusive)
* begin: the first element in the range. (Inclusive)
* end : the last element in the range. (Exclusive)
* end : the last element in the range. (Exclusive)
* step : the distance between two consecutive elements in a range.
* step : the distance between two consecutive elements in a range.
where each element in the range is defined by:
where each element in the range is defined by:
element = begin + step * i
element = begin + step * i
* i: is the index of the element in range.
* i: is the index of the element in range.
The following precondition must be met for the sequence
The following precondition must be met for the sequence
to be a valid range:
to be a valid range:
step != 0
step != 0
&&
&&
(
(
begin <= end && step > 0
begin <= end && step > 0
||
||
begin >= end && step < 0
begin >= end && step < 0
)
)
Portability
Portability
===========
===========
Range Generator is written in standard C++ (C++98). It depends
Range Generator is written in standard C++ (C++98). It depends
-only- on the standard C++ library.
-only- on the standard C++ library.
*/
*/
// TODO: See if we should swap this out for our own implementation, for now this is fine, as it is self contained.
// TODO: See if we should swap this out for our own implementation, for now this is fine, as it is self contained.
/**
/**
* Notes on Modification:
* Notes on Modification:
* The code was adpated to fit into our namespacing/naming scheme for simpler use.
* The code was adpated to fit into our namespacing/naming scheme for simpler use.
* This includes ifdef's, namespace and code formatting style.
* This includes ifdef's, namespace and code formatting style.
*/
*/
#ifndef PLS_range_h__
#ifndef PLS_range_h__
#define PLS_range_h__
#define PLS_range_h__
#include <iterator>
#include <iterator>
#include <stdexcept>
#include <stdexcept>
#include <cstddef>
#include <cstddef>
#include <cmath>
#include <cmath>
namespace
pls
{
namespace
pls
{
namespace
internal
{
namespace
internal
{
namespace
helpers
{
namespace
helpers
{
template
<
class
IntegerType
>
template
<
class
IntegerType
>
struct
basic_range
{
struct
basic_range
{
struct
const_iterator_impl
{
struct
const_iterator_impl
{
typedef
IntegerType
value_type
;
typedef
IntegerType
value_type
;
typedef
std
::
size_t
size_type
;
typedef
std
::
size_t
size_type
;
typedef
IntegerType
difference_type
;
typedef
IntegerType
difference_type
;
typedef
value_type
*
pointer
;
typedef
value_type
*
pointer
;
typedef
value_type
&
reference
;
typedef
value_type
&
reference
;
typedef
typedef
std
::
random_access_iterator_tag
std
::
random_access_iterator_tag
iterator_category
;
iterator_category
;
const_iterator_impl
()
:
r
(
0
),
index
(
0
)
{}
const_iterator_impl
()
:
r
(
0
),
index
(
0
)
{}
const_iterator_impl
(
const
const_iterator_impl
&
rhs
)
const_iterator_impl
(
const
const_iterator_impl
&
rhs
)
:
r
(
rhs
.
r
),
index
(
rhs
.
index
)
{}
:
r
(
rhs
.
r
),
index
(
rhs
.
index
)
{}
const_iterator_impl
(
basic_range
<
IntegerType
>
const
*
p_range
,
size_type
p_index
)
const_iterator_impl
(
basic_range
<
IntegerType
>
const
*
p_range
,
size_type
p_index
)
:
r
(
*
p_range
),
index
(
p_index
)
{}
:
r
(
p_range
),
index
(
p_index
)
{}
const_iterator_impl
&
operator
=
(
const
const_iterator_impl
&
rhs
)
{
const_iterator_impl
&
operator
=
(
const
const_iterator_impl
&
rhs
)
{
r
=
rhs
.
r
;
r
=
rhs
.
r
;
index
=
rhs
.
index
;
index
=
rhs
.
index
;
return
*
this
;
return
*
this
;
}
}
bool
operator
==
(
const
const_iterator_impl
&
rhs
)
const
{
bool
operator
==
(
const
const_iterator_impl
&
rhs
)
const
{
return
r
==
rhs
.
r
&&
index
==
rhs
.
index
;
return
*
r
==
*
(
rhs
.
r
)
&&
index
==
rhs
.
index
;
}
}
bool
operator
!=
(
const
const_iterator_impl
&
rhs
)
const
{
bool
operator
!=
(
const
const_iterator_impl
&
rhs
)
const
{
return
!
(
*
this
==
rhs
);
return
!
(
*
this
==
rhs
);
}
}
bool
operator
<
(
const
const_iterator_impl
&
rhs
)
const
{
bool
operator
<
(
const
const_iterator_impl
&
rhs
)
const
{
return
index
<
rhs
.
index
;
return
index
<
rhs
.
index
;
}
}
bool
operator
>
(
const
const_iterator_impl
&
rhs
)
const
{
bool
operator
>
(
const
const_iterator_impl
&
rhs
)
const
{
return
index
>
rhs
.
index
;
return
index
>
rhs
.
index
;
}
}
bool
operator
<=
(
const
const_iterator_impl
&
rhs
)
const
{
bool
operator
<=
(
const
const_iterator_impl
&
rhs
)
const
{
return
index
<=
rhs
.
index
;
return
index
<=
rhs
.
index
;
}
}
bool
operator
>=
(
const
const_iterator_impl
&
rhs
)
const
{
bool
operator
>=
(
const
const_iterator_impl
&
rhs
)
const
{
return
index
>=
rhs
.
index
;
return
index
>=
rhs
.
index
;
}
}
value_type
operator
*
()
const
{
value_type
operator
*
()
const
{
return
r
.
m_first_element
+
r
.
m_step
*
index
;
return
r
->
m_first_element
+
r
->
m_step
*
index
;
}
}
// operator->
// operator->
// is not implemented because the value_type is an integer type
// is not implemented because the value_type is an integer type
// and primitive types in C++ don't define member functions.
// and primitive types in C++ don't define member functions.
const_iterator_impl
&
operator
++
()
{
const_iterator_impl
&
operator
++
()
{
++
index
;
++
index
;
return
*
this
;
return
*
this
;
}
}
const_iterator_impl
operator
++
(
int
)
{
const_iterator_impl
operator
++
(
int
)
{
const_iterator_impl
temp
=
*
this
;
const_iterator_impl
temp
=
*
this
;
++
index
;
++
index
;
return
temp
;
return
temp
;
}
}
const_iterator_impl
&
operator
--
()
{
const_iterator_impl
&
operator
--
()
{
--
index
;
--
index
;
return
*
this
;
return
*
this
;
}
}
const_iterator_impl
operator
--
(
int
)
{
const_iterator_impl
operator
--
(
int
)
{
const_iterator_impl
temp
=
*
this
;
const_iterator_impl
temp
=
*
this
;
--
index
;
--
index
;
return
temp
;
return
temp
;
}
}
const_iterator_impl
&
operator
+=
(
difference_type
increment
)
{
const_iterator_impl
&
operator
+=
(
difference_type
increment
)
{
index
+=
increment
;
index
+=
increment
;
return
*
this
;
return
*
this
;
}
}
// operator+
// operator+
// is friend operator but operator-
// is friend operator but operator-
// is not, because we want to allow the following for "+":
// is not, because we want to allow the following for "+":
// iterator+5
// iterator+5
// 5+iterator
// 5+iterator
// For the "-" it is not correct to do so, because
// For the "-" it is not correct to do so, because
// iterator-5 != 5-iterator
// iterator-5 != 5-iterator
friend
const_iterator_impl
operator
+
friend
const_iterator_impl
operator
+
(
const
const_iterator_impl
&
lhs
,
difference_type
increment
)
{
(
const
const_iterator_impl
&
lhs
,
difference_type
increment
)
{
const_iterator_impl
sum
;
const_iterator_impl
sum
;
sum
.
r
=
lhs
.
r
;
sum
.
r
=
lhs
.
r
;
sum
.
index
=
lhs
.
index
+
increment
;
sum
.
index
=
lhs
.
index
+
increment
;
return
sum
;
return
sum
;
}
}
const_iterator_impl
&
operator
-=
(
difference_type
decrement
)
{
const_iterator_impl
&
operator
-=
(
difference_type
decrement
)
{
index
-=
decrement
;
index
-=
decrement
;
return
*
this
;
return
*
this
;
}
}
const_iterator_impl
operator
-
(
difference_type
decrement
)
const
{
const_iterator_impl
operator
-
(
difference_type
decrement
)
const
{
const_iterator_impl
shifted_iterator
;
const_iterator_impl
shifted_iterator
;
shifted_iterator
.
r
=
r
;
shifted_iterator
.
r
=
r
;
shifted_iterator
.
index
=
index
-
decrement
;
shifted_iterator
.
index
=
index
-
decrement
;
return
shifted_iterator
;
return
shifted_iterator
;
}
}
difference_type
operator
-
(
const
const_iterator_impl
&
rhs
)
const
{
difference_type
operator
-
(
const
const_iterator_impl
&
rhs
)
const
{
return
index
-
rhs
.
index
;
return
index
-
rhs
.
index
;
}
}
value_type
operator
[](
difference_type
offset
)
const
{
value_type
operator
[](
difference_type
offset
)
const
{
size_type
new_index
=
index
+
offset
;
size_type
new_index
=
index
+
offset
;
return
r
.
m_first_element
+
r
.
m_step
*
new_index
;
return
r
->
m_first_element
+
r
->
m_step
*
new_index
;
}
}
private
:
private
:
basic_range
<
IntegerType
>
r
;
basic_range
<
IntegerType
>
const
*
r
;
size_type
index
;
size_type
index
;
};
};
struct
const_reverse_iterator_impl
{
struct
const_reverse_iterator_impl
{
typedef
IntegerType
value_type
;
typedef
IntegerType
value_type
;
typedef
std
::
size_t
size_type
;
typedef
std
::
size_t
size_type
;
typedef
IntegerType
difference_type
;
typedef
IntegerType
difference_type
;
typedef
value_type
*
pointer
;
typedef
value_type
*
pointer
;
typedef
value_type
&
reference
;
typedef
value_type
&
reference
;
typedef
typedef
std
::
random_access_iterator_tag
std
::
random_access_iterator_tag
iterator_category
;
iterator_category
;
const_reverse_iterator_impl
()
:
r
(
0
),
index
(
0
)
{}
const_reverse_iterator_impl
()
:
r
(
0
),
index
(
0
)
{}
const_reverse_iterator_impl
(
const
const_reverse_iterator_impl
&
rhs
)
const_reverse_iterator_impl
(
const
const_reverse_iterator_impl
&
rhs
)
:
r
(
rhs
.
r
),
index
(
rhs
.
index
)
{}
:
r
(
rhs
.
r
),
index
(
rhs
.
index
)
{}
const_reverse_iterator_impl
(
basic_range
<
IntegerType
>
const
*
p_range
,
size_type
p_index
)
const_reverse_iterator_impl
(
basic_range
<
IntegerType
>
const
*
p_range
,
size_type
p_index
)
:
r
(
*
p_range
),
index
(
p_index
)
{}
:
r
(
p_range
),
index
(
p_index
)
{}
const_reverse_iterator_impl
&
operator
=
(
const
const_reverse_iterator_impl
&
rhs
)
{
const_reverse_iterator_impl
&
operator
=
(
const
const_reverse_iterator_impl
&
rhs
)
{
r
=
rhs
.
r
;
r
=
rhs
.
r
;
index
=
rhs
.
index
;
index
=
rhs
.
index
;
return
*
this
;
return
*
this
;
}
}
bool
operator
==
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
bool
operator
==
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
return
r
==
rhs
.
r
&&
index
==
rhs
.
index
;
return
*
r
==
*
(
rhs
.
r
)
&&
index
==
rhs
.
index
;
}
}
bool
operator
!=
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
bool
operator
!=
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
return
!
(
*
this
==
rhs
);
return
!
(
*
this
==
rhs
);
}
}
bool
operator
<
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
bool
operator
<
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
return
index
<
rhs
.
index
;
return
index
<
rhs
.
index
;
}
}
bool
operator
>
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
bool
operator
>
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
return
index
>
rhs
.
index
;
return
index
>
rhs
.
index
;
}
}
bool
operator
<=
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
bool
operator
<=
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
return
index
<=
rhs
.
index
;
return
index
<=
rhs
.
index
;
}
}
bool
operator
>=
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
bool
operator
>=
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
return
index
>=
rhs
.
index
;
return
index
>=
rhs
.
index
;
}
}
value_type
operator
*
()
const
{
value_type
operator
*
()
const
{
size_type
reverse_index
size_type
reverse_index
=
(
r
.
m_element_count
-
1
)
-
index
;
=
(
r
->
m_element_count
-
1
)
-
index
;
return
r
.
m_first_element
+
r
.
m_step
*
reverse_index
;
return
r
->
m_first_element
+
r
->
m_step
*
reverse_index
;
}
}
// operator->
// operator->
// is not implemented because the value_type is integer type
// is not implemented because the value_type is integer type
// and primitive types in C++ don't define member functions.
// and primitive types in C++ don't define member functions.
const_reverse_iterator_impl
&
operator
++
()
{
const_reverse_iterator_impl
&
operator
++
()
{
++
index
;
++
index
;
return
*
this
;
return
*
this
;
}
}
const_reverse_iterator_impl
operator
++
(
int
)
{
const_reverse_iterator_impl
operator
++
(
int
)
{
const_reverse_iterator_impl
temp
=
*
this
;
const_reverse_iterator_impl
temp
=
*
this
;
++
index
;
++
index
;
return
temp
;
return
temp
;
}
}
const_reverse_iterator_impl
&
operator
--
()
{
const_reverse_iterator_impl
&
operator
--
()
{
--
index
;
--
index
;
return
*
this
;
return
*
this
;
}
}
const_reverse_iterator_impl
operator
--
(
int
)
{
const_reverse_iterator_impl
operator
--
(
int
)
{
const_reverse_iterator_impl
temp
=
*
this
;
const_reverse_iterator_impl
temp
=
*
this
;
--
index
;
--
index
;
return
temp
;
return
temp
;
}
}
const_reverse_iterator_impl
&
operator
+=
(
difference_type
increment
)
{
const_reverse_iterator_impl
&
operator
+=
(
difference_type
increment
)
{
index
+=
increment
;
index
+=
increment
;
return
*
this
;
return
*
this
;
}
}
// operator+
// operator+
// is friend operator but operator-
// is friend operator but operator-
// is not, because we want to allow the following for "+":
// is not, because we want to allow the following for "+":
// iterator+5
// iterator+5
// 5+iterator
// 5+iterator
// For the "-" it is not correct to do so, because
// For the "-" it is not correct to do so, because
// iterator-5 != 5-iterator
// iterator-5 != 5-iterator
friend
const_reverse_iterator_impl
operator
+
friend
const_reverse_iterator_impl
operator
+
(
const
const_reverse_iterator_impl
&
lhs
,
difference_type
increment
)
{
(
const
const_reverse_iterator_impl
&
lhs
,
difference_type
increment
)
{
const_reverse_iterator_impl
sum
;
const_reverse_iterator_impl
sum
;
sum
.
r
=
lhs
.
r
;
sum
.
r
=
lhs
.
r
;
sum
.
index
=
lhs
.
index
+
increment
;
sum
.
index
=
lhs
.
index
+
increment
;
return
sum
;
return
sum
;
}
}
const_reverse_iterator_impl
&
operator
-=
(
difference_type
decrement
)
{
const_reverse_iterator_impl
&
operator
-=
(
difference_type
decrement
)
{
index
-=
decrement
;
index
-=
decrement
;
return
*
this
;
return
*
this
;
}
}
const_reverse_iterator_impl
operator
-
(
difference_type
decrement
)
const
{
const_reverse_iterator_impl
operator
-
(
difference_type
decrement
)
const
{
const_reverse_iterator_impl
shifted_iterator
;
const_reverse_iterator_impl
shifted_iterator
;
shifted_iterator
.
r
=
r
;
shifted_iterator
.
r
=
r
;
shifted_iterator
.
index
=
index
-
decrement
;
shifted_iterator
.
index
=
index
-
decrement
;
return
shifted_iterator
;
return
shifted_iterator
;
}
}
difference_type
operator
-
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
difference_type
operator
-
(
const
const_reverse_iterator_impl
&
rhs
)
const
{
return
index
-
rhs
.
index
;
return
index
-
rhs
.
index
;
}
}
value_type
operator
[](
difference_type
offset
)
const
{
value_type
operator
[](
difference_type
offset
)
const
{
size_type
new_reverse_index
size_type
new_reverse_index
=
(
r
.
m_element_count
-
1
)
-
(
index
+
offset
);
=
(
r
->
m_element_count
-
1
)
-
(
index
+
offset
);
return
r
.
m_first_element
+
r
.
m_step
*
new_reverse_index
;
return
r
->
m_first_element
+
r
->
m_step
*
new_reverse_index
;
}
}
private
:
private
:
basic_range
<
IntegerType
>
r
;
basic_range
<
IntegerType
>
const
*
r
;
size_type
index
;
size_type
index
;
};
};
typedef
IntegerType
value_type
;
typedef
IntegerType
value_type
;
typedef
const_iterator_impl
iterator
;
typedef
const_iterator_impl
iterator
;
typedef
const_iterator_impl
const_iterator
;
typedef
const_iterator_impl
const_iterator
;
typedef
const_reverse_iterator_impl
reverse_iterator
;
typedef
const_reverse_iterator_impl
reverse_iterator
;
typedef
const_reverse_iterator_impl
const_reverse_iterator
;
typedef
const_reverse_iterator_impl
const_reverse_iterator
;
typedef
value_type
&
reference
;
typedef
value_type
&
reference
;
typedef
const
value_type
&
const_reference
;
typedef
const
value_type
&
const_reference
;
typedef
value_type
*
pointer
;
typedef
value_type
*
pointer
;
typedef
IntegerType
difference_type
;
typedef
IntegerType
difference_type
;
typedef
std
::
size_t
size_type
;
typedef
std
::
size_t
size_type
;
// In the case of default construction,
// In the case of default construction,
// the range is considered as an empty range with no elements.
// the range is considered as an empty range with no elements.
// step can be anything other than 0. 1 is
// step can be anything other than 0. 1 is
// an implementation convention, and it doesn't have
// an implementation convention, and it doesn't have
// a significance in this case because the range is empty.
// a significance in this case because the range is empty.
basic_range
()
:
m_first_element
(
0
),
m_element_count
(
0
),
m_step
(
1
)
{}
basic_range
()
:
m_first_element
(
0
),
m_element_count
(
0
),
m_step
(
1
)
{}
// first_element: is begin in specifications.
// first_element: is begin in specifications.
// last_element: is end in specifications.
// last_element: is end in specifications.
basic_range
(
value_type
first_element
,
value_type
last_element
,
value_type
step
)
basic_range
(
value_type
first_element
,
value_type
last_element
,
value_type
step
)
:
m_first_element
(
first_element
),
:
m_first_element
(
first_element
),
m_step
(
step
)
{
m_step
(
step
)
{
// We need to count the number of elements.
// We need to count the number of elements.
// The only case where a range is invalid,
// The only case where a range is invalid,
// when the step=0. It means that the range
// when the step=0. It means that the range
// is infinite, because the number of elements
// is infinite, because the number of elements
// in a range, is the length of that range
// in a range, is the length of that range
// divided by the difference between
// divided by the difference between
// every two successive elements.
// every two successive elements.
if
(
step
==
0
)
if
(
step
==
0
)
throw
std
::
out_of_range
(
"Invalid Range: step can't be equal to zero!"
);
throw
std
::
out_of_range
(
"Invalid Range: step can't be equal to zero!"
);
if
(
first_element
<
last_element
&&
step
<
0
)
if
(
first_element
<
last_element
&&
step
<
0
)
throw
std
::
out_of_range
(
"Invalid Range: step can't be backward, while the range is forward!"
);
throw
std
::
out_of_range
(
"Invalid Range: step can't be backward, while the range is forward!"
);
if
(
first_element
>
last_element
&&
step
>
0
)
if
(
first_element
>
last_element
&&
step
>
0
)
throw
std
::
out_of_range
(
"Invalid Range: step can't be forward, while the range is backward!"
);
throw
std
::
out_of_range
(
"Invalid Range: step can't be forward, while the range is backward!"
);
m_element_count
=
(
last_element
-
first_element
)
/
step
;
m_element_count
=
(
last_element
-
first_element
)
/
step
;
if
((
last_element
-
first_element
)
%
step
!=
0
)
if
((
last_element
-
first_element
)
%
step
!=
0
)
++
m_element_count
;
++
m_element_count
;
}
}
// The following constructor, determines the step
// The following constructor, determines the step
// automatically. If the range is forward, then
// automatically. If the range is forward, then
// step will be one. If the range is backward,
// step will be one. If the range is backward,
// step will be minus one. If the begin is equal
// step will be minus one. If the begin is equal
// to end, then the step must not equal to zero
// to end, then the step must not equal to zero
// and it is set to one as a convention.
// and it is set to one as a convention.
basic_range
(
value_type
first_element
,
value_type
last_element
)
basic_range
(
value_type
first_element
,
value_type
last_element
)
:
m_first_element
(
first_element
)
{
:
m_first_element
(
first_element
)
{
if
(
last_element
>=
first_element
)
*
this
=
basic_range
<
IntegerType
>
(
first_element
,
last_element
,
1
);
if
(
last_element
>=
first_element
)
*
this
=
basic_range
<
IntegerType
>
(
first_element
,
last_element
,
1
);
else
*
this
=
basic_range
<
IntegerType
>
(
first_element
,
last_element
,
-
1
);
else
*
this
=
basic_range
<
IntegerType
>
(
first_element
,
last_element
,
-
1
);
}
}
// The following constructor is a shortcut
// The following constructor is a shortcut
// if you want the first element as zero.
// if you want the first element as zero.
// the step is determined automatically, based
// the step is determined automatically, based
// on the last element. If the last element is
// on the last element. If the last element is
// positive, then step is one, but if it is negative
// positive, then step is one, but if it is negative
// then step is minus one.
// then step is minus one.
basic_range
<
IntegerType
>
(
value_type
last_element
)
basic_range
<
IntegerType
>
(
value_type
last_element
)
:
m_first_element
(
0
)
{
:
m_first_element
(
0
)
{
if
(
last_element
>=
m_first_element
)
*
this
=
basic_range
<
IntegerType
>
(
m_first_element
,
last_element
,
1
);
if
(
last_element
>=
m_first_element
)
*
this
=
basic_range
<
IntegerType
>
(
m_first_element
,
last_element
,
1
);
else
*
this
=
basic_range
<
IntegerType
>
(
m_first_element
,
last_element
,
-
1
);
else
*
this
=
basic_range
<
IntegerType
>
(
m_first_element
,
last_element
,
-
1
);
}
}
basic_range
<
IntegerType
>
(
const
basic_range
<
IntegerType
>
&
r
)
basic_range
<
IntegerType
>
(
const
basic_range
<
IntegerType
>
&
r
)
:
m_first_element
(
r
.
m_first_element
),
:
m_first_element
(
r
.
m_first_element
),
m_element_count
(
r
.
m_element_count
),
m_element_count
(
r
.
m_element_count
),
m_step
(
r
.
m_step
)
{}
m_step
(
r
.
m_step
)
{}
basic_range
<
IntegerType
>
&
operator
=
(
const
basic_range
<
IntegerType
>
&
r
)
{
basic_range
<
IntegerType
>
&
operator
=
(
const
basic_range
<
IntegerType
>
&
r
)
{
m_first_element
=
r
.
m_first_element
;
m_first_element
=
r
.
m_first_element
;
m_element_count
=
r
.
m_element_count
;
m_element_count
=
r
.
m_element_count
;
m_step
=
r
.
m_step
;
m_step
=
r
.
m_step
;
return
*
this
;
return
*
this
;
}
}
bool
operator
==
(
const
basic_range
<
IntegerType
>
&
r
)
const
{
bool
operator
==
(
const
basic_range
<
IntegerType
>
&
r
)
const
{
return
m_first_element
==
r
.
m_first_element
return
m_first_element
==
r
.
m_first_element
&&
&&
m_element_count
==
r
.
m_element_count
m_element_count
==
r
.
m_element_count
&&
&&
m_step
==
r
.
m_step
;
m_step
==
r
.
m_step
;
}
}
bool
operator
!=
(
const
basic_range
<
IntegerType
>
&
r
)
const
{
bool
operator
!=
(
const
basic_range
<
IntegerType
>
&
r
)
const
{
return
!
(
*
this
==
r
);
return
!
(
*
this
==
r
);
}
}
// The following four functions enable the user to compare
// The following four functions enable the user to compare
// ranges using ( <, >, <=, >=).
// ranges using ( <, >, <=, >=).
// The comparison between two ranges is a simple lexicographical
// The comparison between two ranges is a simple lexicographical
// comparison(element by element). By convention, if two ranges
// comparison(element by element). By convention, if two ranges
// R1, R2 where R1 has a smaller number of elements. Then if
// R1, R2 where R1 has a smaller number of elements. Then if
// R1 contains more elements but all R1 elements are found in R2
// R1 contains more elements but all R1 elements are found in R2
// R1 is considered less than R2.
// R1 is considered less than R2.
bool
operator
<
(
const
basic_range
<
IntegerType
>
&
r
)
const
{
bool
operator
<
(
const
basic_range
<
IntegerType
>
&
r
)
const
{
// ********** This function needs refactoring.
// ********** This function needs refactoring.
if
(
m_element_count
==
0
&&
r
.
m_element_count
==
0
)
if
(
m_element_count
==
0
&&
r
.
m_element_count
==
0
)
return
false
;
return
false
;
if
(
m_element_count
==
0
&&
r
.
m_element_count
>
0
)
if
(
m_element_count
==
0
&&
r
.
m_element_count
>
0
)
return
true
;
return
true
;
if
(
m_element_count
>
0
&&
r
.
m_element_count
==
0
)
if
(
m_element_count
>
0
&&
r
.
m_element_count
==
0
)
return
false
;
return
false
;
// At this point, both has at least one element.
// At this point, both has at least one element.
if
(
m_first_element
<
r
.
m_first_element
)
if
(
m_first_element
<
r
.
m_first_element
)
return
true
;
return
true
;
if
(
m_first_element
>
r
.
m_first_element
)
if
(
m_first_element
>
r
.
m_first_element
)
return
false
;
return
false
;
// At this point, the first element of both are equal.
// At this point, the first element of both are equal.
if
(
m_element_count
==
1
&&
r
.
m_element_count
==
1
)
if
(
m_element_count
==
1
&&
r
.
m_element_count
==
1
)
return
false
;
return
false
;
if
(
m_element_count
==
1
&&
r
.
m_element_count
>
1
)
if
(
m_element_count
==
1
&&
r
.
m_element_count
>
1
)
return
true
;
return
true
;
if
(
m_element_count
>
1
&&
r
.
m_element_count
==
1
)
if
(
m_element_count
>
1
&&
r
.
m_element_count
==
1
)
return
false
;
return
false
;
// At this point, both have at least two elements with
// At this point, both have at least two elements with
// a similar first element. Note than the final answer
// a similar first element. Note than the final answer
// in this case depends on the second element only, because
// in this case depends on the second element only, because
// we don't need to compare the elements further.
// we don't need to compare the elements further.
// Note that the second element is at (index == 1), because
// Note that the second element is at (index == 1), because
// the first element is at (index == 0).
// the first element is at (index == 0).
if
(
m_first_element
+
m_step
*
1
<
r
.
m_first_element
+
r
.
m_step
*
1
)
if
(
m_first_element
+
m_step
*
1
<
r
.
m_first_element
+
r
.
m_step
*
1
)
return
true
;
return
true
;
if
(
m_first_element
+
m_step
*
1
>
r
.
m_first_element
+
r
.
m_step
*
1
)
if
(
m_first_element
+
m_step
*
1
>
r
.
m_first_element
+
r
.
m_step
*
1
)
return
false
;
return
false
;
// if the first two elements of both ranges are equal, then
// if the first two elements of both ranges are equal, then
// they are co-linear ranges(because the step is constant).
// they are co-linear ranges(because the step is constant).
// In that case, they comparison depends only on
// In that case, they comparison depends only on
// the size of the ranges by convention.
// the size of the ranges by convention.
return
m_element_count
<
r
.
m_element_count
;
return
m_element_count
<
r
.
m_element_count
;
}
}
bool
operator
>
(
const
basic_range
<
IntegerType
>
&
r
)
const
{
bool
operator
>
(
const
basic_range
<
IntegerType
>
&
r
)
const
{
// ********** This function needs refactoring.
// ********** This function needs refactoring.
if
(
m_element_count
==
0
&&
r
.
m_element_count
==
0
)
if
(
m_element_count
==
0
&&
r
.
m_element_count
==
0
)
return
false
;
return
false
;
if
(
m_element_count
==
0
&&
r
.
m_element_count
>
0
)
if
(
m_element_count
==
0
&&
r
.
m_element_count
>
0
)
return
false
;
return
false
;
if
(
m_element_count
>
0
&&
r
.
m_element_count
==
0
)
if
(
m_element_count
>
0
&&
r
.
m_element_count
==
0
)
return
true
;
return
true
;
// At this point, both has at least one element.
// At this point, both has at least one element.
if
(
m_first_element
<
r
.
m_first_element
)
if
(
m_first_element
<
r
.
m_first_element
)
return
false
;
return
false
;
if
(
m_first_element
>
r
.
m_first_element
)
if
(
m_first_element
>
r
.
m_first_element
)
return
true
;
return
true
;
// At this point, the first element of both are equal.
// At this point, the first element of both are equal.
if
(
m_element_count
==
1
&&
r
.
m_element_count
==
1
)
if
(
m_element_count
==
1
&&
r
.
m_element_count
==
1
)
return
false
;
return
false
;
if
(
m_element_count
==
1
&&
r
.
m_element_count
>
1
)
if
(
m_element_count
==
1
&&
r
.
m_element_count
>
1
)
return
false
;
return
false
;
if
(
m_element_count
>
1
&&
r
.
m_element_count
==
1
)
if
(
m_element_count
>
1
&&
r
.
m_element_count
==
1
)
return
true
;
return
true
;
// At this point, both have at least two elements with
// At this point, both have at least two elements with
// a similar first element. Note than the final answer
// a similar first element. Note than the final answer
// in this case depends on the second element only, because
// in this case depends on the second element only, because
// we don't need to compare the elements further.
// we don't need to compare the elements further.
// Note that the second element is at (index == 1), because
// Note that the second element is at (index == 1), because
// the first element is at (index == 0).
// the first element is at (index == 0).
if
(
m_first_element
+
m_step
*
1
<
r
.
m_first_element
+
r
.
m_step
*
1
)
if
(
m_first_element
+
m_step
*
1
<
r
.
m_first_element
+
r
.
m_step
*
1
)
return
false
;
return
false
;
if
(
m_first_element
+
m_step
*
1
>
r
.
m_first_element
+
r
.
m_step
*
1
)
if
(
m_first_element
+
m_step
*
1
>
r
.
m_first_element
+
r
.
m_step
*
1
)
return
true
;
return
true
;
// if the first two elements of both ranges are equal, then
// if the first two elements of both ranges are equal, then
// they are co-linear ranges(because the step is constant).
// they are co-linear ranges(because the step is constant).
// In that case, they comparison depends only on
// In that case, they comparison depends only on
// the size of the ranges by convention.
// the size of the ranges by convention.
return
m_element_count
>
r
.
m_element_count
;
return
m_element_count
>
r
.
m_element_count
;
}
}
bool
operator
<=
(
const
basic_range
<
IntegerType
>
&
r
)
const
{
bool
operator
<=
(
const
basic_range
<
IntegerType
>
&
r
)
const
{
return
!
(
*
this
>
r
);
return
!
(
*
this
>
r
);
}
}
bool
operator
>=
(
const
basic_range
<
IntegerType
>
&
r
)
const
{
bool
operator
>=
(
const
basic_range
<
IntegerType
>
&
r
)
const
{
return
!
(
*
this
<
r
);
return
!
(
*
this
<
r
);
}
}
const_iterator
begin
()
const
{
const_iterator
begin
()
const
{
return
const_iterator
(
this
,
0
);
return
const_iterator
(
this
,
0
);
}
}
const_iterator
end
()
const
{
const_iterator
end
()
const
{
return
const_iterator
(
this
,
m_element_count
);
return
const_iterator
(
this
,
m_element_count
);
}
}
const_reverse_iterator
rbegin
()
const
{
const_reverse_iterator
rbegin
()
const
{
return
const_reverse_iterator
(
this
,
0
);
return
const_reverse_iterator
(
this
,
0
);
}
}
const_reverse_iterator
rend
()
const
{
const_reverse_iterator
rend
()
const
{
return
const_reverse_iterator
(
this
,
m_element_count
);
return
const_reverse_iterator
(
this
,
m_element_count
);
}
}
size_type
size
()
const
{
size_type
size
()
const
{
return
m_element_count
;
return
m_element_count
;
}
}
size_type
max_size
()
const
{
size_type
max_size
()
const
{
// Because this is an immutable container,
// Because this is an immutable container,
// max_size() == size()
// max_size() == size()
return
m_element_count
;
return
m_element_count
;
}
}
bool
empty
()
const
{
bool
empty
()
const
{
return
m_element_count
==
0
;
return
m_element_count
==
0
;
}
}
// exist() and find() are similar except that
// exist() and find() are similar except that
// find() returns the index of the element.
// find() returns the index of the element.
iterator
find
(
value_type
element
)
const
{
iterator
find
(
value_type
element
)
const
{
value_type
element_index
=
(
element
-
m_first_element
)
/
m_step
;
value_type
element_index
=
(
element
-
m_first_element
)
/
m_step
;
bool
in_range
=
element_index
>=
0
&&
element_index
<
m_element_count
&&
bool
in_range
=
element_index
>=
0
&&
element_index
<
m_element_count
&&
(
element
-
m_first_element
)
%
m_step
==
0
;
(
element
-
m_first_element
)
%
m_step
==
0
;
if
(
in_range
)
if
(
in_range
)
return
begin
()
+
element_index
;
return
begin
()
+
element_index
;
return
end
();
return
end
();
}
}
bool
exist
(
value_type
element
)
const
{
bool
exist
(
value_type
element
)
const
{
return
find
(
element
)
!=
end
();
return
find
(
element
)
!=
end
();
}
}
// In the standard, the operator[]
// In the standard, the operator[]
// should return a const reference.
// should return a const reference.
// Because Range Generator doesn't store its elements
// Because Range Generator doesn't store its elements
// internally, we return a copy of the value.
// internally, we return a copy of the value.
// In any case, this doesn't affect the semantics of the operator.
// In any case, this doesn't affect the semantics of the operator.
value_type
operator
[](
size_type
index
)
const
{
value_type
operator
[](
size_type
index
)
const
{
return
m_first_element
+
m_step
*
index
;
return
m_first_element
+
m_step
*
index
;
}
}
private
:
private
:
// m_first_element: begin (see specifications).
// m_first_element: begin (see specifications).
// m_element_count: (end - begin) / step
// m_element_count: (end - begin) / step
value_type
m_first_element
,
m_element_count
,
m_step
;
value_type
m_first_element
,
m_element_count
,
m_step
;
};
};
// This is the default type of range!
// This is the default type of range!
typedef
basic_range
<
int
>
range
;
typedef
basic_range
<
int
>
range
;
}
}
}
}
}
}
#endif // range_h__
#endif // range_h__
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment