Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Klepl Jiří
asgn
Commits
b86a15d9
Commit
b86a15d9
authored
May 05, 2020
by
s_kleplj
Browse files
.
parent
74d4d707
Changes
1
Hide whitespace changes
Inline
Side-by-side
sol/bsearchsol.hpp
View file @
b86a15d9
...
...
@@ -3,52 +3,254 @@
#include <cstdint>
#include <utility>
#include <limits>
#include <vector>
#include <immintrin.h>
///////////////////////////////
namespace
bsearchsol
{
using
data_element
=
std
::
int32_t
;
using
data_element
=
std
::
int32_t
;
template
<
typename
policy
>
class
bsearch_outer
;
template
<
typename
policy
>
class
bsearch_inner
{
public:
bsearch_inner
(
const
data_element
*
data
,
std
::
size_t
size
)
{
struct
policy_scalar
{
};
struct
policy_sse
{
};
struct
policy_avx
{
};
struct
policy_avx512
{
};
template
<
typename
policy
>
struct
policy_data_base
{
using
data_packed
=
std
::
size_t
;
};
template
<
>
struct
policy_data_base
<
policy_sse
>
{
using
data_packed
=
__m128i
;
};
#ifdef USE_AVX
template
<
>
struct
policy_data_base
<
policy_avx
>
{
using
data_packed
=
__m256i
;
};
#endif
#ifdef USE_AVX512
template
<
>
struct
policy_data_base
<
policy_avx512
>
{
using
data_packed
=
std
::
uint32_t
[
16
];
};
#endif
template
<
typename
policy
>
struct
policy_data
{
using
data_packed
=
typename
policy_data_base
<
policy
>::
data_packed
;
static
constexpr
std
::
size_t
pack_size
=
sizeof
(
data_packed
)
/
sizeof
(
data_element
);
};
template
<
typename
policy
,
std
::
size_t
size
>
struct
get_jump_long
{
private:
static
constexpr
std
::
size_t
pack_size
=
policy_data
<
policy
>::
pack_size
;
public:
using
value_type
=
std
::
size_t
;
static
constexpr
value_type
value
=
size
>
pack_size
*
pack_size
?
get_jump_long
<
policy
,
size
/
pack_size
>::
value
*
pack_size
+
pack_size
:
0
;
};
template
<
typename
policy
,
std
::
size_t
size
>
struct
get_jump
{
private:
static
constexpr
std
::
size_t
pack_size
=
policy_data
<
policy
>::
pack_size
;
public:
using
value_type
=
std
::
size_t
;
static
constexpr
value_type
value
=
size
>
pack_size
*
pack_size
?
get_jump_long
<
policy
,
size
/
pack_size
>::
value
*
pack_size
+
pack_size
:
size
/
pack_size
;
};
template
<
typename
policy
,
std
::
size_t
size
>
struct
get_real_jump
{
private:
public:
using
value_type
=
std
::
size_t
;
static
constexpr
value_type
value
=
get_jump
<
policy
,
size
>::
value
/
policy_data
<
policy
>::
pack_size
;
};
template
<
typename
policy
,
std
::
size_t
size
>
struct
next_size
{
private:
static
constexpr
std
::
size_t
pack_size
=
policy_data
<
policy
>::
pack_size
;
public:
using
value_type
=
std
::
size_t
;
static
constexpr
value_type
value
=
size
>
pack_size
?
size
/
pack_size
:
1
;
};
constexpr
std
::
size_t
i
=
get_jump
<
policy_avx512
,
8192
>::
value
;
template
<
typename
policy
>
class
bsearch_inner
{
using
data_packed
=
typename
policy_data
<
policy
>::
data_packed
;
static
constexpr
std
::
size_t
pack_size
=
policy_data
<
policy
>::
pack_size
;
public:
bsearch_inner
(
const
data_element
*
data
,
std
::
size_t
size
)
:
structure
{}
,
isize
{
size
}
{
append_data
(
data
,
isize
/
pack_size
,
isize
);
for
(
std
::
size_t
i
=
0
;
i
<
isize
;
++
i
)
{
structure
.
emplace_back
(
data
[
i
]);
}
}
;
}
template
<
typename
policy
>
class
bsearch_outer
{
public:
bsearch_outer
(
const
bsearch_inner
<
policy
>&
inner
,
std
::
size_t
osize
)
{
void
append_data
(
const
data_element
*
data
,
std
::
size_t
step
,
std
::
size_t
count
)
{
if
(
step
>
1
)
{
for
(
std
::
size_t
i
=
step
;
i
<=
count
;
i
+=
step
)
{
structure
.
emplace_back
(
data
[
i
-
1
]);
}
for
(
std
::
size_t
i
=
0
;
i
<=
count
;
i
+=
step
)
{
append_data
(
data
+
i
,
step
/
pack_size
,
step
);
}
}
}
void
bucketize
(
const
data_element
*
data
)
// size of data is osize
std
::
size_t
find
(
const
data_element
num
)
const
{
switch
(
isize
)
{
case
64
:
return
_find
<
64
>
(
0
,
num
);
break
;
case
256
:
return
_find
<
256
>
(
0
,
num
);
break
;
case
1024
:
return
_find
<
1024
>
(
0
,
num
);
break
;
case
4096
:
return
_find
<
4096
>
(
0
,
num
);
break
;
case
16384
:
return
_find
<
16384
>
(
0
,
num
);
break
;
case
262144
:
return
_find
<
262144
>
(
0
,
num
);
break
;
case
1048576
:
return
_find
<
1048576
>
(
0
,
num
);
break
;
}
using
bucket_rv
=
std
::
pair
<
const
data_element
*
,
std
::
size_t
>
;
return
0
;
}
bucket_rv
bucket
(
std
::
size_t
k
)
const
{
return
bucket_rv
(
0
,
0
);
// return reference to bucket contents
}
}
;
const
std
::
size_t
&
size
(
)
const
{
return
isize
;
}
private:
template
<
std
::
size_t
size
>
std
::
size_t
_find
(
const
std
::
size_t
offset
,
const
data_element
num
)
const
;
struct
policy_scalar
{
};
std
::
vector
<
data_element
>
structure
;
std
::
size_t
isize
;
};
struct
policy_sse
{
};
template
<
typename
policy
>
template
<
std
::
size_t
size
>
std
::
size_t
bsearch_inner
<
policy
>::
_find
(
const
std
::
size_t
offset
,
const
data_element
num
)
const
{
return
0
;
}
struct
policy_avx
{
};
static
const
__m128i
popcount_mask
=
_mm_set1_epi8
(
0x0F
);
static
const
__m128i
popcount_table
=
_mm_setr_epi8
(
0
,
1
,
1
,
2
,
1
,
2
,
2
,
3
,
1
,
2
,
2
,
3
,
2
,
3
,
3
,
4
);
static
inline
__m128i
popcnt8
(
__m128i
n
)
{
const
__m128i
pcnt0
=
_mm_shuffle_epi8
(
popcount_table
,
_mm_and_si128
(
n
,
popcount_mask
));
const
__m128i
pcnt1
=
_mm_shuffle_epi8
(
popcount_table
,
_mm_and_si128
(
_mm_srli_epi16
(
n
,
4
),
popcount_mask
));
return
_mm_add_epi8
(
pcnt0
,
pcnt1
);
}
struct
policy_avx512
{
};
template
<
>
template
<
std
::
size_t
size
>
inline
std
::
size_t
bsearch_inner
<
policy_sse
>::
_find
(
const
std
::
size_t
offset
,
const
data_element
num
)
const
{
auto
tmp
=
_mm_cmplt_epi32
(
_mm_loadu_si128
((
data_packed
*
)
&
structure
[
offset
]),
_mm_set1_epi32
(
num
));
return
_find
<
next_size
<
policy_sse
,
size
>::
value
>
(
offset
+
pack_size
+
(
__builtin_popcount
(
_mm_movemask_epi8
(
tmp
))
>>
2
)
*
get_jump
<
policy_sse
,
size
>::
value
,
num
);
}
template
<
>
template
<
>
inline
std
::
size_t
bsearch_inner
<
policy_sse
>::
_find
<
1
>
(
const
std
::
size_t
offset
,
const
data_element
num
)
const
{
auto
tmp
=
_mm_cmplt_epi32
(
_mm_loadu_si128
((
data_packed
*
)
&
structure
[
offset
]),
_mm_set1_epi32
(
num
));
return
__builtin_popcount
(
_mm_movemask_epi8
(
tmp
))
>>
2
;
}
#endif
template
<
std
::
size_t
base
,
std
::
size_t
exp
>
struct
pow
{
using
value_type
=
std
::
size_t
;
static
constexpr
value_type
value
=
pow
<
base
,
exp
-
1
>::
value
*
base
;
};
template
<
std
::
size_t
base
>
struct
pow
<
base
,
0
>
{
using
value_type
=
std
::
size_t
;
static
constexpr
value_type
value
=
1
;
};
template
<
typename
policy
>
class
bsearch_outer
{
using
data_packed
=
typename
policy_data
<
policy
>::
data_packed
;
static
constexpr
std
::
size_t
pack_size
=
sizeof
(
data_packed
)
/
sizeof
(
data_element
);
public:
bsearch_outer
(
const
bsearch_inner
<
policy
>&
inner
,
std
::
size_t
osize
)
:
inner_
{
inner
}
,
osize_
{
osize
}
,
buckets_
(
inner
.
size
()
+
1
)
{
}
void
bucketize
(
const
data_element
*
data
)
// size of data is osize
{
for
(
const
data_element
*
p_data
=
data
+
osize_
;
--
p_data
!=
data
;
)
{
buckets_
[
inner_
.
find
(
*
p_data
)].
emplace_back
(
*
p_data
);
}
}
using
bucket_rv
=
std
::
pair
<
const
data_element
*
,
std
::
size_t
>
;
bucket_rv
bucket
(
std
::
size_t
k
)
const
{
return
bucket_rv
(
buckets_
[
k
].
data
(),
buckets_
[
k
].
size
());
// return reference to bucket contents
}
const
bsearch_inner
<
policy
>&
inner_
;
std
::
vector
<
std
::
vector
<
data_element
>>
buckets_
;
const
std
::
size_t
osize_
;
};
}
#endif
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