Skip to content

Commit f2b048a

Browse files
committed
Direct implementation of segmented_fill[_n], calling segmented_generate[_n] can be suboptimal in some compilers.
1 parent 1586338 commit f2b048a

2 files changed

Lines changed: 230 additions & 4 deletions

File tree

include/boost/container/experimental/segmented_fill.hpp

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,113 @@
2121
#include <boost/container/detail/config_begin.hpp>
2222
#include <boost/container/detail/workaround.hpp>
2323
#include <boost/container/experimental/segmented_iterator_traits.hpp>
24-
#include <boost/container/experimental/segmented_generate.hpp>
24+
#include <boost/container/detail/iterator.hpp>
25+
#include <boost/container/experimental/segmented_fill_n.hpp>
2526

2627
namespace boost {
2728
namespace container {
2829

30+
template <class FwdIt, class Sent, class T>
31+
void segmented_fill(FwdIt first, Sent last, const T& value);
32+
33+
namespace detail_algo {
34+
35+
#if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING)
36+
37+
template <class RAIter, class T>
38+
void segmented_fill_range
39+
(RAIter first, RAIter last, const T& value, const non_segmented_iterator_tag &, const std::random_access_iterator_tag &)
40+
{
41+
typedef typename iterator_traits<RAIter>::difference_type difference_type;
42+
43+
difference_type n = last - first;
44+
while(n >= difference_type(4)) {
45+
*first = value; ++first;
46+
*first = value; ++first;
47+
*first = value; ++first;
48+
*first = value; ++first;
49+
n -= 4;
50+
}
51+
52+
switch(n) {
53+
case 3:
54+
*first = value; ++first;
55+
BOOST_FALLTHROUGH;
56+
case 2:
57+
*first = value; ++first;
58+
BOOST_FALLTHROUGH;
59+
case 1:
60+
*first = value;
61+
BOOST_FALLTHROUGH;
62+
default:
63+
break;
64+
}
65+
}
66+
67+
#endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING
68+
69+
template <class FwdIt, class Sent, class T, class Tag, class Cat>
70+
BOOST_CONTAINER_FORCEINLINE typename algo_enable_if_c<
71+
!Tag::value || is_sentinel<Sent, FwdIt>::value>::type
72+
segmented_fill_range(FwdIt first, Sent last, const T& value, Tag, Cat)
73+
{
74+
for(; first != last; ++first)
75+
*first = value;
76+
}
77+
78+
template <class SegIter, class T, class Cat>
79+
void segmented_fill_range
80+
(SegIter first, SegIter last, const T& value, segmented_iterator_tag, Cat)
81+
{
82+
typedef segmented_iterator_traits<SegIter> traits;
83+
typedef typename traits::local_iterator local_iterator;
84+
typedef typename traits::segment_iterator segment_iterator;
85+
typedef typename segmented_iterator_traits<local_iterator>::is_segmented_iterator is_local_seg_t;
86+
typedef typename iterator_traits<local_iterator>::iterator_category local_cat_t;
87+
88+
segment_iterator sfirst = traits::segment(first);
89+
segment_iterator slast = traits::segment(last);
90+
91+
if(sfirst == slast) {
92+
(segmented_fill_range)(traits::local(first), traits::local(last), value, is_local_seg_t(), local_cat_t());
93+
}
94+
else {
95+
(segmented_fill_range)(traits::local(first), traits::end(sfirst), value, is_local_seg_t(), local_cat_t());
96+
97+
for(++sfirst; sfirst != slast; ++sfirst)
98+
(segmented_fill_range)(traits::begin(sfirst), traits::end(sfirst), value, is_local_seg_t(), local_cat_t());
99+
100+
(segmented_fill_range)(traits::begin(sfirst), traits::local(last), value, is_local_seg_t(), local_cat_t());
101+
}
102+
}
103+
104+
template <class FwdIt, class T>
105+
BOOST_CONTAINER_FORCEINLINE
106+
void segmented_fill_dispatch(FwdIt first, FwdIt last, const T& value, const std::random_access_iterator_tag &)
107+
{
108+
(segmented_fill_n)(first, last - first, value);
109+
}
110+
111+
template <class FwdIt, class Sent, class T, class Cat>
112+
BOOST_CONTAINER_FORCEINLINE
113+
void segmented_fill_dispatch(FwdIt first, Sent last, const T& value, const Cat &)
114+
{
115+
typedef segmented_iterator_traits<FwdIt> traits;
116+
(segmented_fill_range)(first, last, value, typename traits::is_segmented_iterator(), Cat());
117+
}
118+
119+
} // namespace detail_algo
120+
29121
//! Assigns \c value to every element in [first, last).
30122
//! When \c Iter is a segmented iterator, exploits segmentation
31123
//! to reduce per-element overhead.
124+
//! When \c Sent is the same type as \c FwdIt and the iterator
125+
//! category is random access, derives to \c segmented_fill_n.
32126
template <class FwdIt, class Sent, class T>
33127
BOOST_CONTAINER_FORCEINLINE
34128
void segmented_fill(FwdIt first, Sent last, const T& value)
35129
{
36-
(segmented_generate)(first, last, detail_algo::constref_generator<T>(value));
130+
detail_algo::segmented_fill_dispatch(first, last, value, typename iterator_traits<FwdIt>::iterator_category());
37131
}
38132

39133
} // namespace container

include/boost/container/experimental/segmented_fill_n.hpp

Lines changed: 134 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,151 @@
2121
#include <boost/container/detail/config_begin.hpp>
2222
#include <boost/container/detail/workaround.hpp>
2323
#include <boost/container/experimental/segmented_iterator_traits.hpp>
24-
#include <boost/container/experimental/segmented_generate_n.hpp>
24+
#include <boost/container/detail/iterators.hpp>
25+
#include <boost/container/detail/std_fwd.hpp>
2526

2627
namespace boost {
2728
namespace container {
2829

30+
template <class FwdIt, class Size, class T>
31+
FwdIt segmented_fill_n(FwdIt first, Size count, const T& value);
32+
33+
namespace detail_algo {
34+
35+
template <class OutIter, class Size, class T>
36+
OutIter fill_n_scan_non_segmented(OutIter first, OutIter last, Size& count, const T& value, const std::random_access_iterator_tag &)
37+
{
38+
std::size_t range_sz = static_cast<std::size_t>(last - first);
39+
const Size local_count = (std::size_t)count < range_sz ? count : (Size)range_sz;
40+
41+
#if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING)
42+
Size cnt = local_count;
43+
while(cnt >= Size(4)) {
44+
*first = value; ++first;
45+
*first = value; ++first;
46+
*first = value; ++first;
47+
*first = value; ++first;
48+
cnt -= Size(4);
49+
}
50+
51+
switch(cnt) {
52+
case 3:
53+
*first = value; ++first;
54+
BOOST_FALLTHROUGH;
55+
case 2:
56+
*first = value; ++first;
57+
BOOST_FALLTHROUGH;
58+
case 1:
59+
*first = value; ++first;
60+
BOOST_FALLTHROUGH;
61+
default:
62+
break;
63+
}
64+
#else
65+
for(Size cnt = local_count; cnt; ++first, --cnt)
66+
*first = value;
67+
#endif
68+
69+
count -= local_count;
70+
return first;
71+
}
72+
73+
template <class OutIter, class Size, class T, class Tag>
74+
OutIter fill_n_scan_non_segmented(OutIter first, OutIter last, Size& count, const T& value, Tag)
75+
{
76+
Size local_count = count;
77+
78+
for (; local_count > 0 && first != last; ++first, --local_count)
79+
*first = value;
80+
81+
count = local_count;
82+
83+
return first;
84+
}
85+
86+
template <class OutIter, class Size, class T>
87+
BOOST_CONTAINER_FORCEINLINE
88+
OutIter fill_n_scan(OutIter first, OutIter last, Size& count, const T& value, non_segmented_iterator_tag)
89+
{
90+
return (fill_n_scan_non_segmented)(first, last, count, value, typename iterator_traits<OutIter>::iterator_category());
91+
}
92+
93+
template <class SegIt, class Size, class T>
94+
SegIt fill_n_scan(SegIt first, SegIt last, Size& count, const T& value, segmented_iterator_tag)
95+
{
96+
typedef segmented_iterator_traits<SegIt> traits;
97+
typedef typename traits::local_iterator local_iterator;
98+
typedef typename traits::segment_iterator segment_iterator;
99+
typedef typename segmented_iterator_traits<local_iterator>::is_segmented_iterator is_local_seg_t;
100+
101+
segment_iterator scur = traits::segment(first);
102+
segment_iterator const slast = traits::segment(last);
103+
104+
if(scur == slast) {
105+
const local_iterator ll = traits::local(last);
106+
const local_iterator r = (fill_n_scan)(traits::local(first), ll, count, value, is_local_seg_t());
107+
return (r != ll) ? traits::compose(scur, r) : last;
108+
}
109+
else {
110+
local_iterator r = fill_n_scan(traits::local(first), traits::end(scur), count, value, is_local_seg_t());
111+
if (!count)
112+
return traits::compose(scur, r);
113+
114+
for (++scur; scur != slast; ++scur) {
115+
r = fill_n_scan(traits::begin(scur), traits::end(scur), count, value, is_local_seg_t());
116+
if (!count)
117+
return traits::compose(scur, r);
118+
}
119+
const local_iterator ll = traits::local(last);
120+
r = fill_n_scan(traits::begin(slast), ll, count, value, is_local_seg_t());
121+
return (r != ll) ? traits::compose(scur, r) : last;
122+
}
123+
}
124+
125+
template <class SegIter, class Size, class T>
126+
SegIter segmented_fill_n_ref
127+
(SegIter first, Size count, const T& value, segmented_iterator_tag)
128+
{
129+
typedef segmented_iterator_traits<SegIter> traits;
130+
typedef typename traits::local_iterator local_iterator;
131+
typedef typename traits::segment_iterator segment_iterator;
132+
typedef typename segmented_iterator_traits<local_iterator>::is_segmented_iterator is_local_seg_t;
133+
134+
segment_iterator scur = traits::segment(first);
135+
local_iterator lcur = traits::local(first);
136+
137+
while(1) {
138+
lcur = fill_n_scan(lcur, traits::end(scur), count, value, is_local_seg_t());
139+
140+
if(count == 0)
141+
break;
142+
++scur;
143+
lcur = traits::begin(scur);
144+
}
145+
return traits::compose(scur, lcur);
146+
}
147+
148+
template <class OutIt, class Size, class T>
149+
OutIt segmented_fill_n_ref
150+
(OutIt first, Size count, const T& value, non_segmented_iterator_tag)
151+
{
152+
for(; count > 0; ++first, --count)
153+
*first = value;
154+
return first;
155+
}
156+
157+
} // namespace detail_algo
158+
29159
//! Assigns \c value to the first \c count elements starting at \c first.
30160
//! Returns an iterator past the last filled element.
31161
//! Exploits segmentation when available.
32162
template <class FwdIt, class Size, class T>
33163
BOOST_CONTAINER_FORCEINLINE
34164
FwdIt segmented_fill_n(FwdIt first, Size count, const T& value)
35165
{
36-
return (segmented_generate_n)(first, count, detail_algo::constref_generator<T>(value));
166+
typedef segmented_iterator_traits<FwdIt> traits;
167+
return detail_algo::segmented_fill_n_ref(first, count, value,
168+
typename traits::is_segmented_iterator());
37169
}
38170

39171
} // namespace container

0 commit comments

Comments
 (0)