Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
LEFEBVREJP email
radix
Commits
427beebe
Commit
427beebe
authored
Aug 06, 2021
by
LEFEBVREJP email
Browse files
Added Greg Davidson's ranges implementation.
parent
166d2cfd
Pipeline
#158067
passed with stages
in 17 minutes and 57 seconds
Changes
5
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
radixcore/CMakeLists.txt
View file @
427beebe
...
...
@@ -8,6 +8,8 @@ json.hh
system.hh
stringfunctions.i.hh
stringfunctions.hh
range.hh
range.i.hh
value.hh
)
SET
(
SOURCES
...
...
radixcore/range.hh
0 → 100644
View file @
427beebe
/*
* @file: range.hh
* @author: Gregory G. Davidson
*
* Created on July 28, 2021
*
* Provides the ability to iterate over ranges in a ranged-for construct
*/
#ifndef RADIX_RADIXCORE_RANGE_HH_
#define RADIX_RADIXCORE_RANGE_HH_
#include <iterator>
#include <type_traits>
namespace
radix
{
namespace
detail
{
// Forward declaration of iterator classes
template
<
class
T
>
class
RangeIterator
;
template
<
class
T
>
class
StridedRangeIterator
;
}
// namespace detail
/**
* @brief Standard range class for iterating over a range
*/
template
<
class
T
>
class
Range
{
public:
using
value_type
=
T
;
using
iterator
=
detail
::
RangeIterator
<
T
>
;
using
size_type
=
std
::
size_t
;
// >>> CONSTRUCTORS
// Default constructor for an empty range
inline
Range
();
// Construct with a range ending (begins at zero)
inline
explicit
Range
(
value_type
end
);
// Construct from a given beginning and ending
inline
Range
(
value_type
begin
,
value_type
end
);
// >>> BASIC CONTAINER FUNCTIONALITY
//! Return beginning of range
iterator
begin
()
const
{
return
d_begin
;
}
//! Return ending of range
iterator
end
()
const
{
return
d_end
;
}
//! Return size of range
size_type
size
()
const
{
return
*
d_end
-
*
d_begin
;
}
//! Return whether range is empty
bool
empty
()
const
{
return
d_begin
==
d_end
;
}
private:
iterator
d_begin
;
iterator
d_end
;
};
/**
* @brief Strided range class for iterating over a range by some stride
*/
template
<
class
T
>
class
StridedRange
{
public:
using
value_type
=
T
;
using
iterator
=
detail
::
StridedRangeIterator
<
T
>
;
using
size_type
=
std
::
size_t
;
// >>> CONSTRUCTORS
// Construct with a range ending and stride
inline
StridedRange
(
value_type
end
,
value_type
stride
);
// Construct with a range beginning, ending, and stride
inline
StridedRange
(
value_type
begin
,
value_type
end
,
value_type
stride
);
// >>> BASIC CONTAINER FUNCTIONALITY
//! Return beginning of range
iterator
begin
()
const
{
return
d_begin
;
}
//! Return ending of range
iterator
end
()
const
{
return
d_end
;
}
//! Return size of range
size_type
size
()
const
{
return
*
d_end
-
*
d_begin
;
}
//! Return whether range is empty
bool
empty
()
const
{
return
d_begin
==
d_end
;
}
private:
iterator
d_begin
;
iterator
d_end
;
};
//*****************************************************************************
// HELPER FUNCTIONS
//*****************************************************************************
// Build an iterable range with a beginning and ending
template
<
class
T
>
Range
<
T
>
range
(
T
begin
,
T
end
);
// Build an iterable range with just an ending
template
<
class
T
>
Range
<
T
>
range
(
T
begin
,
T
end
);
// Build a strided range with a beginning, ending, and stride
template
<
class
T
>
StridedRange
<
T
>
range
(
T
begin
,
T
end
,
T
stride
);
namespace
detail
{
/**
* @brief Range iterator class
*/
template
<
class
T
>
class
RangeIterator
{
public:
//@{
//! Public types
using
iterator_category
=
std
::
input_iterator_tag
;
using
value_type
=
T
;
using
difference_type
=
typename
std
::
make_signed
<
T
>::
type
;
using
pointer
=
const
T
*
;
using
reference
=
const
T
&
;
using
This
=
RangeIterator
<
T
>
;
//@}
public:
// Construct with value
inline
explicit
RangeIterator
(
value_type
value
);
// >>> ITERATOR INTERFACE
//! Dereference operator
value_type
operator
*
()
const
{
return
d_value
;
}
//! Indirection operator
pointer
operator
->
()
const
{
return
&
d_value
;
}
// Prefix increment operator
inline
This
&
operator
++
();
// Postfix increment operator
inline
This
operator
++
(
int
);
//! Equality operator
inline
bool
operator
==
(
const
This
&
iter
)
const
;
//! Inequality operator
inline
bool
operator
!=
(
const
This
&
iter
)
const
;
protected:
value_type
d_value
;
};
//*****************************************************************************
/**
* @brief Strided range iterator class
*/
template
<
class
T
>
class
StridedRangeIterator
:
public
RangeIterator
<
T
>
{
using
Base
=
RangeIterator
<
T
>
;
public:
using
typename
Base
::
value_type
;
using
This
=
StridedRangeIterator
<
T
>
;
public:
// Construct with value and stride
inline
StridedRangeIterator
(
value_type
value
,
value_type
stride
);
// >>> OVERWRITTEN ITERATOR INTERFACE
// Prefix increment operator
inline
This
&
operator
++
();
//! Equality operator
inline
bool
operator
==
(
const
This
&
iter
)
const
;
// >>> CLASS INTERFACE
value_type
stride
()
const
{
return
d_stride
;
}
private:
value_type
d_stride
;
};
}
// namespace detail
}
// namespace radix
//*****************************************************************************
// Inline function definitions
#include "range.i.hh"
//*****************************************************************************
#endif
/** RADIX_RADIXCORE_RANGE_HH_ */
radixcore/range.i.hh
0 → 100644
View file @
427beebe
/*
* @file: range.i.hh
* @author: Gregory G. Davidson
*
* Created on July 28, 2021
*/
#include <cmath>
#include "radixbug/bug.hh"
namespace
{
// Return 1 or -1 matching the sign of the argument
template
<
class
T
>
T
sign
(
T
value
)
{
return
std
::
signbit
(
value
)
?
-
1
:
1
;
}
}
// namespace
namespace
radix
{
//*****************************************************************************
// RANGE
//*****************************************************************************
/*!
* \brief Default constructor for empty range
*/
template
<
class
T
>
Range
<
T
>::
Range
()
:
Range
(
value_type
(
0
),
value_type
(
0
))
{
radix_ensure
(
this
->
empty
());
}
//*****************************************************************************
/*!
* \brief Constructor with range beginning at zero
*/
template
<
class
T
>
Range
<
T
>::
Range
(
value_type
end
)
:
Range
(
T
(
0
),
end
)
{
/* * */
}
//*****************************************************************************
/*!
* \brief Constructor with a beginnning and ending range
*/
template
<
class
T
>
Range
<
T
>::
Range
(
value_type
begin
,
value_type
end
)
:
d_begin
(
begin
)
,
d_end
(
end
)
{
radix_require
(
begin
<=
end
);
}
//*****************************************************************************
// STRIDEDRANGE
//*****************************************************************************
/*!
* \brief Construct with a range ending and stride
*/
template
<
class
T
>
StridedRange
<
T
>::
StridedRange
(
value_type
end
,
value_type
stride
)
:
StridedRange
(
value_type
(
0
),
end
,
stride
)
{
/* * */
}
//*****************************************************************************
/*!
* \brief Construct with a range begining, ending, and stride
*/
template
<
class
T
>
StridedRange
<
T
>::
StridedRange
(
value_type
begin
,
value_type
end
,
value_type
stride
)
:
d_begin
(
begin
,
stride
)
,
d_end
(
end
,
stride
)
{
radix_require
(
end
>=
sign
(
stride
)
*
begin
);
}
//*****************************************************************************
// HELPER FUNCTIONS
//*****************************************************************************
/*!
* \brief Build an iterable range with a beginning and ending
*/
template
<
class
T
>
Range
<
T
>
range
(
T
begin
,
T
end
)
{
return
Range
<
T
>
(
begin
,
end
);
}
//*****************************************************************************
/*!
* \brief Build an iterable range with just an ending
*/
template
<
class
T
>
Range
<
T
>
range
(
T
end
)
{
return
Range
<
T
>
(
end
);
}
//*****************************************************************************
/*!
* \brief Build a strided, iterable range with a beginning, ending, and stride
*/
template
<
class
T
>
StridedRange
<
T
>
range
(
T
begin
,
T
end
,
T
stride
)
{
return
StridedRange
<
T
>
(
begin
,
end
,
stride
);
}
namespace
detail
{
//*****************************************************************************
// RANGEITERATOR
//*****************************************************************************
/*!
* \brief Constructor
*/
template
<
class
T
>
RangeIterator
<
T
>::
RangeIterator
(
value_type
value
)
:
d_value
(
value
)
{
/* * */
}
//*****************************************************************************
/*!
* \brief Prefix increment operator
*/
template
<
class
T
>
auto
RangeIterator
<
T
>::
operator
++
()
->
This
&
{
++
d_value
;
return
*
this
;
}
//*****************************************************************************
/*!
* \brief Postfix increment operator
*/
template
<
class
T
>
auto
RangeIterator
<
T
>::
operator
++
(
int
)
->
This
{
This
copy
=
*
this
;
++
(
*
this
);
return
copy
;
}
//*****************************************************************************
/*!
* \brief Equality operator
*/
template
<
class
T
>
bool
RangeIterator
<
T
>::
operator
==
(
const
This
&
iter
)
const
{
return
d_value
==
iter
.
d_value
;
}
//*****************************************************************************
/*!
* \brief Inequality operator
*/
template
<
class
T
>
bool
RangeIterator
<
T
>::
operator
!=
(
const
This
&
iter
)
const
{
return
!
this
->
operator
==
(
iter
);
}
//*****************************************************************************
// STRIDEDRANGEITERATOR
//*****************************************************************************
/*!
* \brief Constructor taking a value and stride
*/
template
<
class
T
>
StridedRangeIterator
<
T
>::
StridedRangeIterator
(
value_type
value
,
value_type
stride
)
:
Base
(
value
)
,
d_stride
(
stride
)
{
radix_require
(
stride
!=
0
);
}
/*!
* \brief Prefix increment
* operator
*/
template
<
class
T
>
auto
StridedRangeIterator
<
T
>::
operator
++
()
->
This
&
{
Base
::
d_value
+=
d_stride
;
return
*
this
;
}
//*****************************************************************************
/*!
* \brief Equality operator
*
* Only iterators of equal stride
* should be compared
*/
template
<
class
T
>
bool
StridedRangeIterator
<
T
>::
operator
==
(
const
This
&
iter
)
const
{
radix_require
(
iter
.
stride
()
==
this
->
stride
());
return
Base
::
d_value
==
iter
.
d_value
;
}
}
// namespace detail
}
// namespace radix
radixcore/tests/CMakeLists.txt
View file @
427beebe
INCLUDE
(
GoogleTest
)
ADD_GOOGLE_TEST
(
tstJson.cc NP 1
)
ADD_GOOGLE_TEST
(
tstRange.cc NP 1
)
ADD_GOOGLE_TEST
(
tstString.cc NP 1
)
ADD_GOOGLE_TEST
(
tstSystem.cc NP 1
)
ADD_GOOGLE_TEST
(
tstValue.cc NP 1
)
...
...
radixcore/tests/tstRange.cc
0 → 100644
View file @
427beebe
#include "gtest/gtest.h"
#include <vector>
#include "radixcore/range.hh"
// Tests simple range starting from zero
TEST
(
RangeTest
,
simple_range
)
{
std
::
vector
<
int
>
v
;
for
(
auto
i
:
radix
::
range
(
10
))
{
v
.
push_back
(
i
);
}
std
::
vector
<
int
>
v_ref
=
{
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
};
EXPECT_EQ
(
v_ref
.
size
(),
v
.
size
());
auto
v_ref_iter
=
v_ref
.
begin
();
for
(
int
v_elem
:
v
)
{
EXPECT_DOUBLE_EQ
(
*
v_ref_iter
++
,
v_elem
);
}
}
// Tests range with a non-zero beginning
TEST
(
RangeTest
,
nonzero_begin_range
)
{
std
::
vector
<
int
>
v
;
for
(
auto
i
:
radix
::
range
(
5
,
10
))
{
v
.
push_back
(
i
);
}
std
::
vector
<
int
>
v_ref
=
{
5
,
6
,
7
,
8
,
9
};
EXPECT_EQ
(
v_ref
.
size
(),
v
.
size
());
auto
v_ref_iter
=
v_ref
.
begin
();
for
(
int
v_elem
:
v
)
{
EXPECT_DOUBLE_EQ
(
*
v_ref_iter
++
,
v_elem
);
}
}
// Tests range with a positive stride
TEST
(
RangeTest
,
pos_stride_test
)
{
std
::
vector
<
int
>
v
;
for
(
auto
i
:
radix
::
range
(
0
,
10
,
2
))
{
v
.
push_back
(
i
);
}
std
::
vector
<
int
>
v_ref
=
{
0
,
2
,
4
,
6
,
8
};
EXPECT_EQ
(
v_ref
.
size
(),
v
.
size
());
auto
v_ref_iter
=
v_ref
.
begin
();
for
(
int
v_elem
:
v
)
{
EXPECT_DOUBLE_EQ
(
*
v_ref_iter
++
,
v_elem
);
}
}
// Tests range with a negative stride
TEST
(
RangeTest
,
neg_stride_test
)
{
std
::
vector
<
int
>
v
;
for
(
auto
i
:
radix
::
range
(
9
,
-
1
,
-
1
))
{
v
.
push_back
(
i
);
}
std
::
vector
<
int
>
v_ref
=
{
9
,
8
,
7
,
6
,
5
,
4
,
3
,
2
,
1
,
0
};
EXPECT_EQ
(
v_ref
.
size
(),
v
.
size
());
auto
v_ref_iter
=
v_ref
.
begin
();
for
(
int
v_elem
:
v
)
{
EXPECT_DOUBLE_EQ
(
*
v_ref_iter
++
,
v_elem
);
}
}
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