| // This code makes some assumptions on the implementation of |
| // base64_stream_encode_init(), base64_stream_encode() and base64_stream_decode(). |
| // Basically these assumptions boil down to that when breaking the src into |
| // parts, out parts can be written without side effects. |
| // This is met when: |
| // 1) base64_stream_encode() and base64_stream_decode() don't use globals; |
| // 2) the shared variables src and out are not read or written outside of the |
| // bounds of their parts, i.e. when base64_stream_encode() reads a multiple |
| // of 3 bytes, it must write no more then a multiple of 4 bytes, not even |
| // temporarily; |
| // 3) the state flag can be discarded after base64_stream_encode() and |
| // base64_stream_decode() on the parts. |
| |
| static inline void |
| base64_encode_openmp |
| ( const char *src |
| , size_t srclen |
| , char *out |
| , size_t *outlen |
| , int flags |
| ) |
| { |
| size_t s; |
| size_t t; |
| size_t sum = 0, len, last_len; |
| struct base64_state state, initial_state; |
| int num_threads, i; |
| |
| // Request a number of threads but not necessarily get them: |
| #pragma omp parallel |
| { |
| // Get the number of threads used from one thread only, |
| // as num_threads is a shared var: |
| #pragma omp single |
| { |
| num_threads = omp_get_num_threads(); |
| |
| // Split the input string into num_threads parts, each |
| // part a multiple of 3 bytes. The remaining bytes will |
| // be done later: |
| len = srclen / (num_threads * 3); |
| len *= 3; |
| last_len = srclen - num_threads * len; |
| |
| // Init the stream reader: |
| base64_stream_encode_init(&state, flags); |
| initial_state = state; |
| } |
| |
| // Single has an implicit barrier for all threads to wait here |
| // for the above to complete: |
| #pragma omp for firstprivate(state) private(s) reduction(+:sum) schedule(static,1) |
| for (i = 0; i < num_threads; i++) |
| { |
| // Feed each part of the string to the stream reader: |
| base64_stream_encode(&state, src + i * len, len, out + i * len * 4 / 3, &s); |
| sum += s; |
| } |
| } |
| |
| // As encoding should never fail and we encode an exact multiple |
| // of 3 bytes, we can discard state: |
| state = initial_state; |
| |
| // Encode the remaining bytes: |
| base64_stream_encode(&state, src + num_threads * len, last_len, out + num_threads * len * 4 / 3, &s); |
| |
| // Finalize the stream by writing trailer if any: |
| base64_stream_encode_final(&state, out + num_threads * len * 4 / 3 + s, &t); |
| |
| // Final output length is stream length plus tail: |
| sum += s + t; |
| *outlen = sum; |
| } |
| |
| static inline int |
| base64_decode_openmp |
| ( const char *src |
| , size_t srclen |
| , char *out |
| , size_t *outlen |
| , int flags |
| ) |
| { |
| int num_threads, result = 0, i; |
| size_t sum = 0, len, last_len, s; |
| struct base64_state state, initial_state; |
| |
| // Request a number of threads but not necessarily get them: |
| #pragma omp parallel |
| { |
| // Get the number of threads used from one thread only, |
| // as num_threads is a shared var: |
| #pragma omp single |
| { |
| num_threads = omp_get_num_threads(); |
| |
| // Split the input string into num_threads parts, each |
| // part a multiple of 4 bytes. The remaining bytes will |
| // be done later: |
| len = srclen / (num_threads * 4); |
| len *= 4; |
| last_len = srclen - num_threads * len; |
| |
| // Init the stream reader: |
| base64_stream_decode_init(&state, flags); |
| |
| initial_state = state; |
| } |
| |
| // Single has an implicit barrier to wait here for the above to |
| // complete: |
| #pragma omp for firstprivate(state) private(s) reduction(+:sum, result) schedule(static,1) |
| for (i = 0; i < num_threads; i++) |
| { |
| int this_result; |
| |
| // Feed each part of the string to the stream reader: |
| this_result = base64_stream_decode(&state, src + i * len, len, out + i * len * 3 / 4, &s); |
| sum += s; |
| result += this_result; |
| } |
| } |
| |
| // If `result' equals `-num_threads', then all threads returned -1, |
| // indicating that the requested codec is not available: |
| if (result == -num_threads) { |
| return -1; |
| } |
| |
| // If `result' does not equal `num_threads', then at least one of the |
| // threads hit a decode error: |
| if (result != num_threads) { |
| return 0; |
| } |
| |
| // So far so good, now decode whatever remains in the buffer. Reuse the |
| // initial state, since we are at a 4-byte boundary: |
| state = initial_state; |
| result = base64_stream_decode(&state, src + num_threads * len, last_len, out + num_threads * len * 3 / 4, &s); |
| sum += s; |
| *outlen = sum; |
| |
| // If when decoding a whole block, we're still waiting for input then fail: |
| if (result && (state.bytes == 0)) { |
| return result; |
| } |
| return 0; |
| } |