#include "mem.h" /* U32, BYTE, etc. */
#include "debug.h" /* assert, DEBUGLOG */
#include "error_private.h" /* ERROR */
#include "hist.h"
unsigned HIST_isError(
size_t
code) {
return
ERR_isError(code); }
unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
const
void
* src,
size_t
srcSize)
{
const
BYTE
* ip = (
const
BYTE
*)src;
const
BYTE
*
const
end = ip + srcSize;
unsigned maxSymbolValue = *maxSymbolValuePtr;
unsigned largestCount=0;
memset
(count, 0, (maxSymbolValue+1) *
sizeof
(*count));
if
(srcSize==0) { *maxSymbolValuePtr = 0;
return
0; }
while
(ip<end) {
assert
(*ip <= maxSymbolValue);
count[*ip++]++;
}
while
(!count[maxSymbolValue]) maxSymbolValue--;
*maxSymbolValuePtr = maxSymbolValue;
{ U32 s;
for
(s=0; s<=maxSymbolValue; s++)
if
(count[s] > largestCount) largestCount = count[s];
}
return
largestCount;
}
typedef
enum
{ trustInput, checkMaxSymbolValue } HIST_checkInput_e;
static
size_t
HIST_count_parallel_wksp(
unsigned* count, unsigned* maxSymbolValuePtr,
const
void
* source,
size_t
sourceSize,
HIST_checkInput_e check,
U32*
const
workSpace)
{
const
BYTE
* ip = (
const
BYTE
*)source;
const
BYTE
*
const
iend = ip+sourceSize;
unsigned maxSymbolValue = *maxSymbolValuePtr;
unsigned max=0;
U32*
const
Counting1 = workSpace;
U32*
const
Counting2 = Counting1 + 256;
U32*
const
Counting3 = Counting2 + 256;
U32*
const
Counting4 = Counting3 + 256;
memset
(workSpace, 0, 4*256*
sizeof
(unsigned));
if
(!sourceSize) {
memset
(count, 0, maxSymbolValue + 1);
*maxSymbolValuePtr = 0;
return
0;
}
if
(!maxSymbolValue) maxSymbolValue = 255;
{ U32 cached = MEM_read32(ip); ip += 4;
while
(ip < iend-15) {
U32 c = cached; cached = MEM_read32(ip); ip += 4;
Counting1[(
BYTE
) c ]++;
Counting2[(
BYTE
)(c>>8) ]++;
Counting3[(
BYTE
)(c>>16)]++;
Counting4[ c>>24 ]++;
c = cached; cached = MEM_read32(ip); ip += 4;
Counting1[(
BYTE
) c ]++;
Counting2[(
BYTE
)(c>>8) ]++;
Counting3[(
BYTE
)(c>>16)]++;
Counting4[ c>>24 ]++;
c = cached; cached = MEM_read32(ip); ip += 4;
Counting1[(
BYTE
) c ]++;
Counting2[(
BYTE
)(c>>8) ]++;
Counting3[(
BYTE
)(c>>16)]++;
Counting4[ c>>24 ]++;
c = cached; cached = MEM_read32(ip); ip += 4;
Counting1[(
BYTE
) c ]++;
Counting2[(
BYTE
)(c>>8) ]++;
Counting3[(
BYTE
)(c>>16)]++;
Counting4[ c>>24 ]++;
}
ip-=4;
}
while
(ip<iend) Counting1[*ip++]++;
if
(check) {
U32 s;
for
(s=255; s>maxSymbolValue; s--) {
Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
if
(Counting1[s])
return
ERROR(maxSymbolValue_tooSmall);
} }
{ U32 s;
if
(maxSymbolValue > 255) maxSymbolValue = 255;
for
(s=0; s<=maxSymbolValue; s++) {
count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
if
(count[s] > max) max = count[s];
} }
while
(!count[maxSymbolValue]) maxSymbolValue--;
*maxSymbolValuePtr = maxSymbolValue;
return
(
size_t
)max;
}
size_t
HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
const
void
* source,
size_t
sourceSize,
void
* workSpace,
size_t
workSpaceSize)
{
if
(sourceSize < 1500)
return
HIST_count_simple(count, maxSymbolValuePtr, source, sourceSize);
if
((
size_t
)workSpace & 3)
return
ERROR(GENERIC);
if
(workSpaceSize < HIST_WKSP_SIZE)
return
ERROR(workSpace_tooSmall);
return
HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, trustInput, (U32*)workSpace);
}
size_t
HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
const
void
* source,
size_t
sourceSize)
{
unsigned tmpCounters[HIST_WKSP_SIZE_U32];
return
HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters,
sizeof
(tmpCounters));
}
size_t
HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
const
void
* source,
size_t
sourceSize,
void
* workSpace,
size_t
workSpaceSize)
{
if
((
size_t
)workSpace & 3)
return
ERROR(GENERIC);
if
(workSpaceSize < HIST_WKSP_SIZE)
return
ERROR(workSpace_tooSmall);
if
(*maxSymbolValuePtr < 255)
return
HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, checkMaxSymbolValue, (U32*)workSpace);
*maxSymbolValuePtr = 255;
return
HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace, workSpaceSize);
}
size_t
HIST_count(unsigned* count, unsigned* maxSymbolValuePtr,
const
void
* src,
size_t
srcSize)
{
unsigned tmpCounters[HIST_WKSP_SIZE_U32];
return
HIST_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters,
sizeof
(tmpCounters));
}