diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b9a603ad8..85715e5791 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,16 +28,23 @@ list(GET VERSION_LIST 0 HIP_VERSION_MAJOR) list(GET VERSION_LIST 1 HIP_VERSION_MINOR) # get date information based on UTC -# use the last two digits of year + week number + day in the week as HIP_VERSION_PATCH +# use the last two digits of year + week number + day in the week as HIP_VERSION_GITDATE # use the commit date, instead of build date # add xargs to remove strange trailing newline character execute_process(COMMAND git show -s --format=@%ct COMMAND xargs COMMAND date -f - --utc +%y%U%w WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - OUTPUT_VARIABLE HIP_VERSION_PATCH + OUTPUT_VARIABLE HIP_VERSION_GITDATE OUTPUT_STRIP_TRAILING_WHITESPACE) +# get commit short hash +execute_process(COMMAND git rev-parse --short HEAD + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE HIP_VERSION_GITHASH + OUTPUT_STRIP_TRAILING_WHITESPACE) + +set(HIP_VERSION_PATCH ${HIP_VERSION_GITDATE}-${HIP_VERSION_GITHASH}) set(HIP_VERSION ${HIP_VERSION_MAJOR}.${HIP_VERSION_MINOR}.${HIP_VERSION_PATCH}) add_to_config(_versionInfo HIP_VERSION_MAJOR) add_to_config(_versionInfo HIP_VERSION_MINOR) @@ -218,7 +225,7 @@ if(HIP_PLATFORM STREQUAL "hcc") endif() # Add HIP_VERSION to CMAKE__FLAGS - set(HIP_HCC_BUILD_FLAGS "${HIP_HCC_BUILD_FLAGS} -DHIP_VERSION_MAJOR=${HIP_VERSION_MAJOR} -DHIP_VERSION_MINOR=${HIP_VERSION_MINOR} -DHIP_VERSION_PATCH=${HIP_VERSION_PATCH}") + set(HIP_HCC_BUILD_FLAGS "${HIP_HCC_BUILD_FLAGS} -DHIP_VERSION_MAJOR=${HIP_VERSION_MAJOR} -DHIP_VERSION_MINOR=${HIP_VERSION_MINOR} -DHIP_VERSION_PATCH=${HIP_VERSION_GITDATE}") # Add remaining flags set(HCC_CXX_FLAGS "-hc -fno-gpu-rdc --amdgpu-target=gfx803 --amdgpu-target=gfx900 --amdgpu-target=gfx906 --amdgpu-target=gfx908 ") @@ -370,7 +377,7 @@ if(HIP_PLATFORM STREQUAL "hcc") write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/hip-config-version.cmake - VERSION "${HIP_VERSION}" + VERSION "${HIP_VERSION_MAJOR}.${HIP_VERSION_MINOR}.${HIP_VERSION_GITDATE}" COMPATIBILITY SameMajorVersion ) install( diff --git a/bin/hipcc b/bin/hipcc index 61f4f1a34e..e8bca65663 100755 --- a/bin/hipcc +++ b/bin/hipcc @@ -102,6 +102,7 @@ sub delete_temp_dirs { $HIP_PLATFORM= `$HIP_PATH/bin/hipconfig --platform` // "hcc"; $HIP_VERSION= `$HIP_PATH/bin/hipconfig --version`; ($HIP_VERSION_MAJOR, $HIP_VERSION_MINOR, $HIP_VERSION_PATCH) = split(/\./, $HIP_VERSION); +my ($HIP_VERSION_GITDATE, $HIP_VERSION_GITHASH) = split(/-/, $HIP_VERSION_PATCH); $HIP_COMPILER= $hipConfig{'HIP_COMPILER'}; $HIP_RUNTIME= $hipConfig{'HIP_RUNTIME'}; @@ -323,7 +324,7 @@ if ($HIP_PLATFORM eq "clang") { } # Add paths to common HIP includes: -$HIPCXXFLAGS .= " -isystem $HIP_INCLUDE_PATH -DHIP_VERSION_MAJOR=$HIP_VERSION_MAJOR -DHIP_VERSION_MINOR=$HIP_VERSION_MINOR -DHIP_VERSION_PATCH=$HIP_VERSION_PATCH" ; +$HIPCXXFLAGS .= " -isystem $HIP_INCLUDE_PATH -DHIP_VERSION_MAJOR=$HIP_VERSION_MAJOR -DHIP_VERSION_MINOR=$HIP_VERSION_MINOR -DHIP_VERSION_PATCH=$HIP_VERSION_GITDATE" ; my $compileOnly = 0; my $needCXXFLAGS = 0; # need to add CXX flags to compile step diff --git a/bin/hipconfig b/bin/hipconfig index caa425e66c..d6ef8a0c4a 100755 --- a/bin/hipconfig +++ b/bin/hipconfig @@ -1,7 +1,7 @@ #!/usr/bin/perl -w -$HIP_BASE_VERSION_MAJOR = "1"; -$HIP_BASE_VERSION_MINOR = "5"; +$HIP_BASE_VERSION_MAJOR = "2"; +$HIP_BASE_VERSION_MINOR = "8"; # Need perl > 5.10 to use logic-defined or use 5.006; use v5.10.1; diff --git a/docs/markdown/CURAND_API_supported_by_HIP.md b/docs/markdown/CURAND_API_supported_by_HIP.md index 0561dd6144..83c41e59ff 100644 --- a/docs/markdown/CURAND_API_supported_by_HIP.md +++ b/docs/markdown/CURAND_API_supported_by_HIP.md @@ -93,16 +93,24 @@ | 11 |*`CURAND_3RD`* | | | 12 |*`CURAND_DEFINITION`* | | | 13 |*`CURAND_POISSON`* | | -| struct | `curandStateMtgp32_t` | `hiprandStateMtgp32_t` | -| struct | `curandStateScrambledSobol64_t` | | -| struct | `curandStateSobol64_t` | | -| struct | `curandStateScrambledSobol32_t` | | -| struct | `curandStateSobol32_t` | `hiprandStateSobol32_t` | -| struct | `curandStateMRG32k3a_t` | `hiprandStateMRG32k3a_t` | -| struct | `curandStatePhilox4_32_10_t` | `hiprandStatePhilox4_32_10_t` | -| struct | `curandStateXORWOW_t` | `hiprandStateXORWOW_t` | -| struct | `curandState_t` | `hiprandState_t` | -| struct | `curandState` | `hiprandState_t` | +| struct | `curandStateMtgp32` | `hiprandStateMtgp32` | +| typedef | `curandStateMtgp32_t` | `hiprandStateMtgp32_t` | +| struct | `curandStateScrambledSobol64` | | +| typedef | `curandStateScrambledSobol64_t` | | +| struct | `curandStateSobol64` | | +| typedef | `curandStateSobol64_t` | | +| struct | `curandStateScrambledSobol32` | | +| typedef | `curandStateScrambledSobol32_t` | | +| struct | `curandStateSobol32` | `hiprandStateSobol32` | +| typedef | `curandStateSobol32_t` | `hiprandStateSobol32_t` | +| struct | `curandStateMRG32k3a` | `hiprandStateMRG32k3a` | +| typedef | `curandStateMRG32k3a_t` | `hiprandStateMRG32k3a_t` | +| struct | `curandStatePhilox4_32_10` | `hiprandStatePhilox4_32_10` | +| typedef | `curandStatePhilox4_32_10_t` | `hiprandStatePhilox4_32_10_t` | +| struct | `curandStateXORWOW` | `hiprandStateXORWOW` | +| typedef | `curandStateXORWOW_t` | `hiprandStateXORWOW_t` | +| struct | `curandState` | `hiprandState` | +| typedef | `curandState_t` | `hiprandState_t` | ## **2. Host API Functions** diff --git a/docs/markdown/hip_porting_guide.md b/docs/markdown/hip_porting_guide.md index 6915945d4e..a2b830ebf1 100644 --- a/docs/markdown/hip_porting_guide.md +++ b/docs/markdown/hip_porting_guide.md @@ -186,8 +186,8 @@ Unlike `__CUDA_ARCH__`, the `__HIP_DEVICE_COMPILE__` value is 1 or undefined, an |Define | hcc | hip-clang | nvcc | Other (GCC, ICC, Clang, etc.) |--- | --- | --- | --- |---| |HIP-related defines:| -|`__HIP_PLATFORM_HCC___`| Defined | Defined | Undefined | Defined if targeting hcc platform; undefined otherwise | -|`__HIP_PLATFORM_NVCC___`| Undefined | Undefined | Defined | Defined if targeting nvcc platform; undefined otherwise | +|`__HIP_PLATFORM_HCC__`| Defined | Defined | Undefined | Defined if targeting hcc platform; undefined otherwise | +|`__HIP_PLATFORM_NVCC__`| Undefined | Undefined | Defined | Defined if targeting nvcc platform; undefined otherwise | |`__HIP_DEVICE_COMPILE__` | 1 if compiling for device; undefined if compiling for host | 1 if compiling for device; undefined if compiling for host |1 if compiling for device; undefined if compiling for host | Undefined |`__HIPCC__` | Defined | Defined | Defined | Undefined |`__HIP_ARCH_*` | 0 or 1 depending on feature support (see below) |0 or 1 depending on feature support (see below) | 0 or 1 depending on feature support (see below) | 0 diff --git a/hipify-clang/src/CUDA2HIP_RAND_API_types.cpp b/hipify-clang/src/CUDA2HIP_RAND_API_types.cpp index 6bf3223cb0..e6eae1db69 100644 --- a/hipify-clang/src/CUDA2HIP_RAND_API_types.cpp +++ b/hipify-clang/src/CUDA2HIP_RAND_API_types.cpp @@ -53,17 +53,24 @@ const std::map CUDA_RAND_TYPE_NAME_MAP{ {"curandDirectionVectors32_t", {"hiprandDirectionVectors32_t", "", CONV_TYPE, API_RAND}}, {"curandDirectionVectors64_t", {"hiprandDirectionVectors64_t", "", CONV_TYPE, API_RAND, HIP_UNSUPPORTED}}, // cuRAND types for Device functions + {"curandStateMtgp32", {"hiprandStateMtgp32", "", CONV_TYPE, API_RAND}}, {"curandStateMtgp32_t", {"hiprandStateMtgp32_t", "", CONV_TYPE, API_RAND}}, + {"curandStateScrambledSobol64", {"hiprandStateScrambledSobol64", "", CONV_TYPE, API_RAND, HIP_UNSUPPORTED}}, {"curandStateScrambledSobol64_t", {"hiprandStateScrambledSobol64_t", "", CONV_TYPE, API_RAND, HIP_UNSUPPORTED}}, + {"curandStateSobol64", {"hiprandStateSobol64", "", CONV_TYPE, API_RAND, HIP_UNSUPPORTED}}, {"curandStateSobol64_t", {"hiprandStateSobol64_t", "", CONV_TYPE, API_RAND, HIP_UNSUPPORTED}}, + {"curandStateScrambledSobol32", {"hiprandStateScrambledSobol32", "", CONV_TYPE, API_RAND, HIP_UNSUPPORTED}}, {"curandStateScrambledSobol32_t", {"hiprandStateScrambledSobol32_t", "", CONV_TYPE, API_RAND, HIP_UNSUPPORTED}}, + {"curandStateSobol32", {"hiprandStateSobol32", "", CONV_TYPE, API_RAND}}, {"curandStateSobol32_t", {"hiprandStateSobol32_t", "", CONV_TYPE, API_RAND}}, + {"curandStateMRG32k3a", {"hiprandStateMRG32k3a", "", CONV_TYPE, API_RAND}}, {"curandStateMRG32k3a_t", {"hiprandStateMRG32k3a_t", "", CONV_TYPE, API_RAND}}, + {"curandStatePhilox4_32_10", {"hiprandStatePhilox4_32_10", "", CONV_TYPE, API_RAND}}, {"curandStatePhilox4_32_10_t", {"hiprandStatePhilox4_32_10_t", "", CONV_TYPE, API_RAND}}, + {"curandStateXORWOW", {"hiprandStateXORWOW", "", CONV_TYPE, API_RAND}}, {"curandStateXORWOW_t", {"hiprandStateXORWOW_t", "", CONV_TYPE, API_RAND}}, + {"curandState", {"hiprandState", "", CONV_TYPE, API_RAND}}, {"curandState_t", {"hiprandState_t", "", CONV_TYPE, API_RAND}}, - {"curandState", {"hiprandState_t", "", CONV_TYPE, API_RAND}}, - // RAND function call status types (enum curandStatus) {"CURAND_STATUS_SUCCESS", {"HIPRAND_STATUS_SUCCESS", "", CONV_NUMERIC_LITERAL, API_RAND}}, diff --git a/include/hip/hcc_detail/hip_runtime_api.h b/include/hip/hcc_detail/hip_runtime_api.h index cec9eb9c94..8db9e23317 100644 --- a/include/hip/hcc_detail/hip_runtime_api.h +++ b/include/hip/hcc_detail/hip_runtime_api.h @@ -1882,15 +1882,27 @@ hipError_t hipMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch, size_t height, hipMemcpyKind kind); /** -* @brief Copies memory for 2D arrays. -* @param[in] pCopy Parameters for the memory copy + * @brief Copies memory for 2D arrays. + * @param[in] pCopy Parameters for the memory copy + * @return #hipSuccess, #hipErrorInvalidValue, #hipErrorInvalidPitchValue, + * #hipErrorInvalidDevicePointer, #hipErrorInvalidMemcpyDirection + * + * @see hipMemcpy, hipMemcpy2D, hipMemcpyToArray, hipMemcpy2DToArray, hipMemcpyFromArray, + * hipMemcpyToSymbol, hipMemcpyAsync +*/ +hipError_t hipMemcpyParam2D(const hip_Memcpy2D* pCopy); + +/** + * @brief Copies memory for 2D arrays. + * @param[in] pCopy Parameters for the memory copy + * @param[in] stream Stream to use * @return #hipSuccess, #hipErrorInvalidValue, #hipErrorInvalidPitchValue, * #hipErrorInvalidDevicePointer, #hipErrorInvalidMemcpyDirection * * @see hipMemcpy, hipMemcpy2D, hipMemcpyToArray, hipMemcpy2DToArray, hipMemcpyFromArray, * hipMemcpyToSymbol, hipMemcpyAsync */ -hipError_t hipMemcpyParam2D(const hip_Memcpy2D* pCopy); +hipError_t hipMemcpyParam2DAsync(const hip_Memcpy2D* pCopy, hipStream_t stream __dparm(0)); /** * @brief Copies data between host and device. diff --git a/include/hip/nvcc_detail/hip_runtime_api.h b/include/hip/nvcc_detail/hip_runtime_api.h index a77d5560d8..ec6ee855c7 100644 --- a/include/hip/nvcc_detail/hip_runtime_api.h +++ b/include/hip/nvcc_detail/hip_runtime_api.h @@ -597,6 +597,10 @@ inline static hipError_t hipMemcpyParam2D(const hip_Memcpy2D* pCopy) { return hipCUResultTohipError(cuMemcpy2D(pCopy)); } +inline static hipError_t hipMemcpyParam2DAsync(const hip_Memcpy2D* pCopy, hipStream_t stream __dparm(0)) { + return hipCUResultTohipError(cuMemcpy2DAsync(pCopy, stream)); +} + inline static hipError_t hipMemcpy3D(const struct hipMemcpy3DParms *p) { return hipCUDAErrorTohipError(cudaMemcpy3D(p)); diff --git a/src/hip_memory.cpp b/src/hip_memory.cpp index 61f34db244..ccea09bb39 100644 --- a/src/hip_memory.cpp +++ b/src/hip_memory.cpp @@ -1694,10 +1694,9 @@ hipError_t hipMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch, return ihipLogStatus(e); } -hipError_t hipMemcpy2DAsync(void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, +hipError_t ihipMemcpy2DAsync(void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, hipMemcpyKind kind, hipStream_t stream) { - HIP_INIT_SPECIAL_API(hipMemcpy2DAsync, (TRACE_MCMD), dst, dpitch, src, spitch, width, height, kind, stream); - if (dst == nullptr || src == nullptr || width > dpitch || width > spitch) return ihipLogStatus(hipErrorInvalidValue); + if (dst == nullptr || src == nullptr || width > dpitch || width > spitch) return hipErrorInvalidValue; hipError_t e = hipSuccess; int isLockedOrD2D = 0; void *pinnedPtr=NULL; @@ -1736,6 +1735,14 @@ hipError_t hipMemcpy2DAsync(void* dst, size_t dpitch, const void* src, size_t sp } } + return e; +} + +hipError_t hipMemcpy2DAsync(void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, + size_t height, hipMemcpyKind kind, hipStream_t stream) { + HIP_INIT_SPECIAL_API(hipMemcpy2DAsync, (TRACE_MCMD), dst, dpitch, src, spitch, width, height, kind, stream); + hipError_t e = hipSuccess; + e = ihipMemcpy2DAsync(dst, dpitch, src, spitch, width, height, kind, stream); return ihipLogStatus(e); } @@ -1744,9 +1751,22 @@ hipError_t hipMemcpyParam2D(const hip_Memcpy2D* pCopy) { hipError_t e = hipSuccess; if (pCopy == nullptr) { e = hipErrorInvalidValue; - } - e = ihipMemcpy2D(pCopy->dstArray->data, pCopy->WidthInBytes, pCopy->srcHost, pCopy->srcPitch, + } else { + e = ihipMemcpy2D(pCopy->dstArray->data, pCopy->WidthInBytes, pCopy->srcHost, pCopy->srcPitch, pCopy->WidthInBytes, pCopy->Height, hipMemcpyDefault); + } + return ihipLogStatus(e); +} + +hipError_t hipMemcpyParam2DAsync(const hip_Memcpy2D* pCopy, hipStream_t stream) { + HIP_INIT_SPECIAL_API(hipMemcpyParam2DAsync, (TRACE_MCMD), pCopy, stream); + hipError_t e = hipSuccess; + if (pCopy == nullptr) { + e = hipErrorInvalidValue; + } else { + e = ihipMemcpy2DAsync(pCopy->dstArray->data, pCopy->WidthInBytes, pCopy->srcHost, pCopy->srcPitch, + pCopy->WidthInBytes, pCopy->Height, hipMemcpyDefault, stream); + } return ihipLogStatus(e); } diff --git a/tests/hipify-clang/unit_tests/libraries/cuRAND/poisson_api_example.cu b/tests/hipify-clang/unit_tests/libraries/cuRAND/poisson_api_example.cu index 4e748973d5..f4fd05ba48 100644 --- a/tests/hipify-clang/unit_tests/libraries/cuRAND/poisson_api_example.cu +++ b/tests/hipify-clang/unit_tests/libraries/cuRAND/poisson_api_example.cu @@ -52,7 +52,7 @@ API_TYPE api; int report_break; int cashiers_load_h[HOURS]; __constant__ int cashiers_load[HOURS]; -// CHECK: __global__ void setup_kernel(hiprandState_t *state) +// CHECK: __global__ void setup_kernel(hiprandState *state) __global__ void setup_kernel(curandState *state) { int id = threadIdx.x + blockIdx.x * blockDim.x; @@ -79,15 +79,15 @@ void update_queue(int id, int min, unsigned int new_customers, = queue_length; } -// CHECK: __global__ void simple_device_API_kernel(hiprandState_t *state, -__global__ void simple_device_API_kernel(curandState *state, +// CHECK: __global__ void simple_device_API_kernel(hiprandState *state, +__global__ void simple_device_API_kernel(curandState *state, unsigned int *queue_lengths, size_t pitch) { int id = threadIdx.x + blockIdx.x * blockDim.x; unsigned int new_customers; unsigned int queue_length = 0; /* Copy state to local memory for efficiency */ - // CHECK: hiprandState_t localState = state[id]; + // CHECK: hiprandState localState = state[id]; curandState localState = state[id]; /* Simulate queue in time */ for(int min = 1; min <= 60 * HOURS; min++) { @@ -120,7 +120,7 @@ __global__ void host_API_kernel(unsigned int *poisson_numbers, queue_lengths, pitch); } } -// CHECK: __global__ void robust_device_API_kernel(hiprandState_t *state, +// CHECK: __global__ void robust_device_API_kernel(hiprandState *state, // CHECK: hiprandDiscreteDistribution_t poisson_1, // CHECK: hiprandDiscreteDistribution_t poisson_2, // CHECK: hiprandDiscreteDistribution_t poisson_3, @@ -134,7 +134,7 @@ __global__ void robust_device_API_kernel(curandState *state, unsigned int new_customers; unsigned int queue_length = 0; /* Copy state to local memory for efficiency */ - // CHECK: hiprandState_t localState = state[id]; + // CHECK: hiprandState localState = state[id]; curandState localState = state[id]; /* Simulate queue in time */ /* first 3 hours */ @@ -165,7 +165,7 @@ __global__ void robust_device_API_kernel(curandState *state, curand_discrete(&localState, poisson_3); /* Update queue */ update_queue(id, min, new_customers, queue_length, - queue_lengths, pitch); + queue_lengths, pitch); } /* Copy state back to global memory */ state[id] = localState; @@ -298,12 +298,11 @@ void print_statistics(unsigned int *hostResults, size_t pitch) } } - int main(int argc, char *argv[]) { int n; size_t pitch; - // CHECK: hiprandState_t *devStates; + // CHECK: hiprandState *devStates; curandState *devStates; unsigned int *devResults, *hostResults; unsigned int *poisson_numbers_d; @@ -328,7 +327,7 @@ int main(int argc, char *argv[]) /* Allocate space for prng states on device */ // CHECK: CUDA_CALL(hipMalloc((void **)&devStates, 64 * 64 * - // CHECK: sizeof(hiprandState_t))); + // CHECK: sizeof(hiprandState))); CUDA_CALL(cudaMalloc((void **)&devStates, 64 * 64 * sizeof(curandState))); diff --git a/tests/src/clara/clara.hpp b/tests/src/clara/clara.hpp new file mode 100644 index 0000000000..10b70da644 --- /dev/null +++ b/tests/src/clara/clara.hpp @@ -0,0 +1,1165 @@ +// v1.0-develop.2 +// See https://github.com/philsquared/Clara + +#ifndef CLARA_HPP_INCLUDED +#define CLARA_HPP_INCLUDED + +#ifndef CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH 80 +#endif + +#ifndef CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#define CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#endif + +// ----------- #included from clara_textflow.hpp ----------- + +// TextFlowCpp +// +// A single-header library for wrapping and laying out basic text, by Phil Nash +// +// This work is licensed under the BSD 2-Clause license. +// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause +// +// This project is hosted at https://github.com/philsquared/textflowcpp + +#ifndef CLARA_TEXTFLOW_HPP_INCLUDED +#define CLARA_TEXTFLOW_HPP_INCLUDED + +#include +#include +#include +#include + +#ifndef CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#define CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 +#endif + + +namespace clara { +namespace TextFlow { + +inline auto isWhitespace(char c) -> bool { + static std::string chars = " \t\n\r"; + return chars.find(c) != std::string::npos; +} +inline auto isBreakableBefore(char c) -> bool { + static std::string chars = "[({<|"; + return chars.find(c) != std::string::npos; +} +inline auto isBreakableAfter(char c) -> bool { + static std::string chars = "])}>.,:;*+-=&/\\"; + return chars.find(c) != std::string::npos; +} + +class Columns; + +class Column { + std::vector m_strings; + size_t m_width = CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; + size_t m_indent = 0; + size_t m_initialIndent = std::string::npos; + + public: + class iterator { + friend Column; + + Column const& m_column; + size_t m_stringIndex = 0; + size_t m_pos = 0; + + size_t m_len = 0; + size_t m_end = 0; + bool m_suffix = false; + + iterator(Column const& column, size_t stringIndex) + : m_column(column), m_stringIndex(stringIndex) {} + + auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } + + auto isBoundary(size_t at) const -> bool { + assert(at > 0); + assert(at <= line().size()); + + return at == line().size() || + (isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) || + isBreakableBefore(line()[at]) || isBreakableAfter(line()[at - 1]); + } + + void calcLength() { + assert(m_stringIndex < m_column.m_strings.size()); + + m_suffix = false; + auto width = m_column.m_width - indent(); + m_end = m_pos; + while (m_end < line().size() && line()[m_end] != '\n') ++m_end; + + if (m_end < m_pos + width) { + m_len = m_end - m_pos; + } else { + size_t len = width; + while (len > 0 && !isBoundary(m_pos + len)) --len; + while (len > 0 && isWhitespace(line()[m_pos + len - 1])) --len; + + if (len > 0) { + m_len = len; + } else { + m_suffix = true; + m_len = width - 1; + } + } + } + + auto indent() const -> size_t { + auto initial = + m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; + return initial == std::string::npos ? m_column.m_indent : initial; + } + + auto addIndentAndSuffix(std::string const& plain) const -> std::string { + return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain); + } + + public: + explicit iterator(Column const& column) : m_column(column) { + assert(m_column.m_width > m_column.m_indent); + assert(m_column.m_initialIndent == std::string::npos || + m_column.m_width > m_column.m_initialIndent); + calcLength(); + if (m_len == 0) m_stringIndex++; // Empty string + } + + auto operator*() const -> std::string { + assert(m_stringIndex < m_column.m_strings.size()); + assert(m_pos <= m_end); + if (m_pos + m_column.m_width < m_end) + return addIndentAndSuffix(line().substr(m_pos, m_len)); + else + return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos)); + } + + auto operator++() -> iterator& { + m_pos += m_len; + if (m_pos < line().size() && line()[m_pos] == '\n') + m_pos += 1; + else + while (m_pos < line().size() && isWhitespace(line()[m_pos])) ++m_pos; + + if (m_pos == line().size()) { + m_pos = 0; + ++m_stringIndex; + } + if (m_stringIndex < m_column.m_strings.size()) calcLength(); + return *this; + } + auto operator++(int) -> iterator { + iterator prev(*this); + operator++(); + return prev; + } + + auto operator==(iterator const& other) const -> bool { + return m_pos == other.m_pos && m_stringIndex == other.m_stringIndex && + &m_column == &other.m_column; + } + auto operator!=(iterator const& other) const -> bool { return !operator==(other); } + }; + using const_iterator = iterator; + + explicit Column(std::string const& text) { m_strings.push_back(text); } + + auto width(size_t newWidth) -> Column& { + assert(newWidth > 0); + m_width = newWidth; + return *this; + } + auto indent(size_t newIndent) -> Column& { + m_indent = newIndent; + return *this; + } + auto initialIndent(size_t newIndent) -> Column& { + m_initialIndent = newIndent; + return *this; + } + + auto width() const -> size_t { return m_width; } + auto begin() const -> iterator { return iterator(*this); } + auto end() const -> iterator { return {*this, m_strings.size()}; } + + inline friend std::ostream& operator<<(std::ostream& os, Column const& col) { + bool first = true; + for (auto line : col) { + if (first) + first = false; + else + os << "\n"; + os << line; + } + return os; + } + + auto operator+(Column const& other) -> Columns; + + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } +}; + +class Spacer : public Column { + public: + explicit Spacer(size_t spaceWidth) : Column("") { width(spaceWidth); } +}; + +class Columns { + std::vector m_columns; + + public: + class iterator { + friend Columns; + struct EndTag {}; + + std::vector const& m_columns; + std::vector m_iterators; + size_t m_activeIterators; + + iterator(Columns const& columns, EndTag) + : m_columns(columns.m_columns), m_activeIterators(0) { + m_iterators.reserve(m_columns.size()); + + for (auto const& col : m_columns) m_iterators.push_back(col.end()); + } + + public: + explicit iterator(Columns const& columns) + : m_columns(columns.m_columns), m_activeIterators(m_columns.size()) { + m_iterators.reserve(m_columns.size()); + + for (auto const& col : m_columns) m_iterators.push_back(col.begin()); + } + + auto operator==(iterator const& other) const -> bool { + return m_iterators == other.m_iterators; + } + auto operator!=(iterator const& other) const -> bool { + return m_iterators != other.m_iterators; + } + auto operator*() const -> std::string { + std::string row, padding; + + for (size_t i = 0; i < m_columns.size(); ++i) { + auto width = m_columns[i].width(); + if (m_iterators[i] != m_columns[i].end()) { + std::string col = *m_iterators[i]; + row += padding + col; + if (col.size() < width) + padding = std::string(width - col.size(), ' '); + else + padding = ""; + } else { + padding += std::string(width, ' '); + } + } + return row; + } + auto operator++() -> iterator& { + for (size_t i = 0; i < m_columns.size(); ++i) { + if (m_iterators[i] != m_columns[i].end()) ++m_iterators[i]; + } + return *this; + } + auto operator++(int) -> iterator { + iterator prev(*this); + operator++(); + return prev; + } + }; + using const_iterator = iterator; + + auto begin() const -> iterator { return iterator(*this); } + auto end() const -> iterator { return {*this, iterator::EndTag()}; } + + auto operator+=(Column const& col) -> Columns& { + m_columns.push_back(col); + return *this; + } + auto operator+(Column const& col) -> Columns { + Columns combined = *this; + combined += col; + return combined; + } + + inline friend std::ostream& operator<<(std::ostream& os, Columns const& cols) { + bool first = true; + for (auto line : cols) { + if (first) + first = false; + else + os << "\n"; + os << line; + } + return os; + } + + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } +}; + +inline auto Column::operator+(Column const& other) -> Columns { + Columns cols; + cols += *this; + cols += other; + return cols; +} +} // namespace TextFlow +} // namespace clara + +#endif // CLARA_TEXTFLOW_HPP_INCLUDED + +// ----------- end of #include from clara_textflow.hpp ----------- +// ........... back in clara.hpp + + +#include +#include +#include + +#if !defined(CLARA_PLATFORM_WINDOWS) && \ + (defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)) +#define CLARA_PLATFORM_WINDOWS +#endif + +namespace clara { +namespace detail { + +// Traits for extracting arg and return type of lambdas (for single argument lambdas) +template +struct UnaryLambdaTraits : UnaryLambdaTraits {}; + +template +struct UnaryLambdaTraits { + static const bool isValid = false; +}; + +template +struct UnaryLambdaTraits { + static const bool isValid = true; + using ArgType = typename std::remove_const::type>::type; + ; + using ReturnType = ReturnT; +}; + +class TokenStream; + +// Transport for raw args (copied from main args, or supplied via init list for testing) +class Args { + friend TokenStream; + std::string m_exeName; + std::vector m_args; + + public: + Args(int argc, char* argv[]) { + m_exeName = argv[0]; + for (int i = 1; i < argc; ++i) m_args.push_back(argv[i]); + } + + Args(std::initializer_list args) + : m_exeName(*args.begin()), m_args(args.begin() + 1, args.end()) {} + + auto exeName() const -> std::string { return m_exeName; } +}; + +// Wraps a token coming from a token stream. These may not directly correspond to strings as a +// single string may encode an option + its argument if the : or = form is used +enum class TokenType { Option, Argument }; +struct Token { + TokenType type; + std::string token; +}; + +inline auto isOptPrefix(char c) -> bool { + return c == '-' +#ifdef CLARA_PLATFORM_WINDOWS + || c == '/' +#endif + ; +} + +// Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled +class TokenStream { + using Iterator = std::vector::const_iterator; + Iterator it; + Iterator itEnd; + std::vector m_tokenBuffer; + + void loadBuffer() { + m_tokenBuffer.resize(0); + + // Skip any empty strings + while (it != itEnd && it->empty()) ++it; + + if (it != itEnd) { + auto const& next = *it; + if (isOptPrefix(next[0])) { + auto delimiterPos = next.find_first_of(" :="); + if (delimiterPos != std::string::npos) { + m_tokenBuffer.push_back({TokenType::Option, next.substr(0, delimiterPos)}); + m_tokenBuffer.push_back({TokenType::Argument, next.substr(delimiterPos + 1)}); + } else { + if (next[1] != '-' && next.size() > 2) { + std::string opt = "- "; + for (size_t i = 1; i < next.size(); ++i) { + opt[1] = next[i]; + m_tokenBuffer.push_back({TokenType::Option, opt}); + } + } else { + m_tokenBuffer.push_back({TokenType::Option, next}); + } + } + } else { + m_tokenBuffer.push_back({TokenType::Argument, next}); + } + } + } + + public: + explicit TokenStream(Args const& args) : TokenStream(args.m_args.begin(), args.m_args.end()) {} + + TokenStream(Iterator it, Iterator itEnd) : it(it), itEnd(itEnd) { loadBuffer(); } + + explicit operator bool() const { return !m_tokenBuffer.empty() || it != itEnd; } + + auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } + + auto operator*() const -> Token { + assert(!m_tokenBuffer.empty()); + return m_tokenBuffer.front(); + } + + auto operator-> () const -> Token const* { + assert(!m_tokenBuffer.empty()); + return &m_tokenBuffer.front(); + } + + auto operator++() -> TokenStream& { + if (m_tokenBuffer.size() >= 2) { + m_tokenBuffer.erase(m_tokenBuffer.begin()); + } else { + if (it != itEnd) ++it; + loadBuffer(); + } + return *this; + } +}; + + +class ResultBase { + public: + enum Type { Ok, LogicError, RuntimeError }; + + protected: + ResultBase(Type type) : m_type(type) {} + virtual ~ResultBase() = default; + + virtual void enforceOk() const = 0; + + Type m_type; +}; + +template +class ResultValueBase : public ResultBase { + public: + auto value() const -> T const& { + enforceOk(); + return m_value; + } + + protected: + ResultValueBase(Type type) : ResultBase(type) {} + + ResultValueBase(ResultValueBase const& other) : ResultBase(other) { + if (m_type == ResultBase::Ok) new (&m_value) T(other.m_value); + } + + ResultValueBase(Type, T const& value) : ResultBase(Ok) { new (&m_value) T(value); } + + auto operator=(ResultValueBase const& other) -> ResultValueBase& { + if (m_type == ResultBase::Ok) m_value.~T(); + ResultBase::operator=(other); + if (m_type == ResultBase::Ok) new (&m_value) T(other.m_value); + return *this; + } + + ~ResultValueBase() { + if (m_type == Ok) m_value.~T(); + } + + union { + T m_value; + }; +}; + +template <> +class ResultValueBase : public ResultBase { + protected: + using ResultBase::ResultBase; +}; + +template +class BasicResult : public ResultValueBase { + public: + template + explicit BasicResult(BasicResult const& other) + : ResultValueBase(other.type()), m_errorMessage(other.errorMessage()) { + assert(type() != ResultBase::Ok); + } + + template + static auto ok(U const& value) -> BasicResult { + return {ResultBase::Ok, value}; + } + static auto ok() -> BasicResult { return {ResultBase::Ok}; } + static auto logicError(std::string const& message) -> BasicResult { + return {ResultBase::LogicError, message}; + } + static auto runtimeError(std::string const& message) -> BasicResult { + return {ResultBase::RuntimeError, message}; + } + + explicit operator bool() const { return m_type == ResultBase::Ok; } + auto type() const -> ResultBase::Type { return m_type; } + auto errorMessage() const -> std::string { return m_errorMessage; } + + protected: + virtual void enforceOk() const { + // !TBD: If no exceptions, std::terminate here or something + switch (m_type) { + case ResultBase::LogicError: + throw std::logic_error(m_errorMessage); + case ResultBase::RuntimeError: + throw std::runtime_error(m_errorMessage); + case ResultBase::Ok: + break; + } + } + + std::string m_errorMessage; // Only populated if resultType is an error + + BasicResult(ResultBase::Type type, std::string const& message) + : ResultValueBase(type), m_errorMessage(message) { + assert(m_type != ResultBase::Ok); + } + + using ResultValueBase::ResultValueBase; + using ResultBase::m_type; +}; + +enum class ParseResultType { Matched, NoMatch, ShortCircuitAll, ShortCircuitSame }; + +class ParseState { + public: + ParseState(ParseResultType type, TokenStream const& remainingTokens) + : m_type(type), m_remainingTokens(remainingTokens) {} + + auto type() const -> ParseResultType { return m_type; } + auto remainingTokens() const -> TokenStream { return m_remainingTokens; } + + private: + ParseResultType m_type; + TokenStream m_remainingTokens; +}; + +using Result = BasicResult; +using ParserResult = BasicResult; +using InternalParseResult = BasicResult; + +struct HelpColumns { + std::string left; + std::string right; +}; + +template +inline auto convertInto(std::string const& source, T& target) -> ParserResult { + std::stringstream ss; + ss << source; + ss >> target; + if (ss.fail()) + return ParserResult::runtimeError("Unable to convert '" + source + "' to destination type"); + else + return ParserResult::ok(ParseResultType::Matched); +} +inline auto convertInto(std::string const& source, std::string& target) -> ParserResult { + target = source; + return ParserResult::ok(ParseResultType::Matched); +} +inline auto convertInto(std::string const& source, bool& target) -> ParserResult { + std::string srcLC = source; + std::transform(srcLC.begin(), srcLC.end(), srcLC.begin(), + [](char c) { return static_cast(::tolower(c)); }); + if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") + target = true; + else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") + target = false; + else + return ParserResult::runtimeError("Expected a boolean value but did not recognise: '" + + source + "'"); + return ParserResult::ok(ParseResultType::Matched); +} + +struct BoundRefBase { + BoundRefBase() = default; + BoundRefBase(BoundRefBase const&) = delete; + BoundRefBase(BoundRefBase&&) = delete; + BoundRefBase& operator=(BoundRefBase const&) = delete; + BoundRefBase& operator=(BoundRefBase&&) = delete; + + virtual ~BoundRefBase() = default; + + virtual auto isFlag() const -> bool = 0; + virtual auto isContainer() const -> bool { return false; } + virtual auto setValue(std::string const& arg) -> ParserResult = 0; + virtual auto setFlag(bool flag) -> ParserResult = 0; +}; + +struct BoundValueRefBase : BoundRefBase { + auto isFlag() const -> bool override { return false; } + + auto setFlag(bool) -> ParserResult override { + return ParserResult::logicError("Flags can only be set on boolean fields"); + } +}; + +struct BoundFlagRefBase : BoundRefBase { + auto isFlag() const -> bool override { return true; } + + auto setValue(std::string const& arg) -> ParserResult override { + bool flag; + auto result = convertInto(arg, flag); + if (result) setFlag(flag); + return result; + } +}; + +template +struct BoundRef : BoundValueRefBase { + T& m_ref; + + explicit BoundRef(T& ref) : m_ref(ref) {} + + auto setValue(std::string const& arg) -> ParserResult override { + return convertInto(arg, m_ref); + } +}; + +template +struct BoundRef> : BoundValueRefBase { + std::vector& m_ref; + + explicit BoundRef(std::vector& ref) : m_ref(ref) {} + + auto isContainer() const -> bool override { return true; } + + auto setValue(std::string const& arg) -> ParserResult override { + T temp; + auto result = convertInto(arg, temp); + if (result) m_ref.push_back(temp); + return result; + } +}; + +struct BoundFlagRef : BoundFlagRefBase { + bool& m_ref; + + explicit BoundFlagRef(bool& ref) : m_ref(ref) {} + + auto setFlag(bool flag) -> ParserResult override { + m_ref = flag; + return ParserResult::ok(ParseResultType::Matched); + } +}; + +template +struct LambdaInvoker { + static_assert(std::is_same::value, + "Lambda must return void or clara::ParserResult"); + + template + static auto invoke(L const& lambda, ArgType const& arg) -> ParserResult { + return lambda(arg); + } +}; + +template <> +struct LambdaInvoker { + template + static auto invoke(L const& lambda, ArgType const& arg) -> ParserResult { + lambda(arg); + return ParserResult::ok(ParseResultType::Matched); + } +}; + +template +inline auto invokeLambda(L const& lambda, std::string const& arg) -> ParserResult { + ArgType temp; + auto result = convertInto(arg, temp); + return !result ? result + : LambdaInvoker::ReturnType>::invoke(lambda, temp); +}; + + +template +struct BoundLambda : BoundValueRefBase { + L m_lambda; + + static_assert(UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument"); + explicit BoundLambda(L const& lambda) : m_lambda(lambda) {} + + auto setValue(std::string const& arg) -> ParserResult override { + return invokeLambda::ArgType>(m_lambda, arg); + } +}; + +template +struct BoundFlagLambda : BoundFlagRefBase { + L m_lambda; + + static_assert(UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument"); + static_assert(std::is_same::ArgType, bool>::value, + "flags must be boolean"); + + explicit BoundFlagLambda(L const& lambda) : m_lambda(lambda) {} + + auto setFlag(bool flag) -> ParserResult override { + return LambdaInvoker::ReturnType>::invoke(m_lambda, flag); + } +}; + +enum class Optionality { Optional, Required }; + +struct Parser; + +class ParserBase { + public: + virtual ~ParserBase() = default; + virtual auto validate() const -> Result { return Result::ok(); } + virtual auto parse(std::string const& exeName, TokenStream const& tokens) const + -> InternalParseResult = 0; + virtual auto cardinality() const -> size_t { return 1; } + + auto parse(Args const& args) const -> InternalParseResult { + return parse(args.exeName(), TokenStream(args)); + } +}; + +template +class ComposableParserImpl : public ParserBase { + public: + template + auto operator|(T const& other) const -> Parser; +}; + +// Common code and state for Args and Opts +template +class ParserRefImpl : public ComposableParserImpl { + protected: + Optionality m_optionality = Optionality::Optional; + std::shared_ptr m_ref; + std::string m_hint; + std::string m_description; + + explicit ParserRefImpl(std::shared_ptr const& ref) : m_ref(ref) {} + + public: + template + ParserRefImpl(T& ref, std::string const& hint) + : m_ref(std::make_shared>(ref)), m_hint(hint) {} + + template + ParserRefImpl(LambdaT const& ref, std::string const& hint) + : m_ref(std::make_shared>(ref)), m_hint(hint) {} + + auto operator()(std::string const& description) -> DerivedT& { + m_description = description; + return static_cast(*this); + } + + auto optional() -> DerivedT& { + m_optionality = Optionality::Optional; + return static_cast(*this); + }; + + auto required() -> DerivedT& { + m_optionality = Optionality::Required; + return static_cast(*this); + }; + + auto isOptional() const -> bool { return m_optionality == Optionality::Optional; } + + auto cardinality() const -> size_t override { + if (m_ref->isContainer()) + return 0; + else + return 1; + } + + auto hint() const -> std::string { return m_hint; } +}; + +class ExeName : public ComposableParserImpl { + std::shared_ptr m_name; + std::shared_ptr m_ref; + + template + static auto makeRef(LambdaT const& lambda) -> std::shared_ptr { + return std::make_shared>(lambda); + } + + public: + ExeName() : m_name(std::make_shared("")) {} + + explicit ExeName(std::string& ref) : ExeName() { + m_ref = std::make_shared>(ref); + } + + template + explicit ExeName(LambdaT const& lambda) : ExeName() { + m_ref = std::make_shared>(lambda); + } + + // The exe name is not parsed out of the normal tokens, but is handled specially + auto parse(std::string const&, TokenStream const& tokens) const + -> InternalParseResult override { + return InternalParseResult::ok(ParseState(ParseResultType::NoMatch, tokens)); + } + + auto name() const -> std::string { return *m_name; } + auto set(std::string const& newName) -> ParserResult { + auto lastSlash = newName.find_last_of("\\/"); + auto filename = (lastSlash == std::string::npos) ? newName : newName.substr(lastSlash + 1); + + *m_name = filename; + if (m_ref) + return m_ref->setValue(filename); + else + return ParserResult::ok(ParseResultType::Matched); + } +}; + +class Arg : public ParserRefImpl { + public: + using ParserRefImpl::ParserRefImpl; + + auto parse(std::string const&, TokenStream const& tokens) const + -> InternalParseResult override { + auto validationResult = validate(); + if (!validationResult) return InternalParseResult(validationResult); + + auto remainingTokens = tokens; + auto const& token = *remainingTokens; + if (token.type != TokenType::Argument) + return InternalParseResult::ok(ParseState(ParseResultType::NoMatch, remainingTokens)); + + auto result = m_ref->setValue(remainingTokens->token); + if (!result) + return InternalParseResult(result); + else + return InternalParseResult::ok(ParseState(ParseResultType::Matched, ++remainingTokens)); + } +}; + +inline auto normaliseOpt(std::string const& optName) -> std::string { +#ifdef CLARA_PLATFORM_WINDOWS + if (optName[0] == '/') + return "-" + optName.substr(1); + else +#endif + return optName; +} + +class Opt : public ParserRefImpl { + protected: + std::vector m_optNames; + + public: + template + explicit Opt(LambdaT const& ref) + : ParserRefImpl(std::make_shared>(ref)) {} + + explicit Opt(bool& ref) : ParserRefImpl(std::make_shared(ref)) {} + + template + Opt(LambdaT const& ref, std::string const& hint) : ParserRefImpl(ref, hint) {} + + template + Opt(T& ref, std::string const& hint) : ParserRefImpl(ref, hint) {} + + auto operator[](std::string const& optName) -> Opt& { + m_optNames.push_back(optName); + return *this; + } + + auto getHelpColumns() const -> std::vector { + std::ostringstream oss; + bool first = true; + for (auto const& opt : m_optNames) { + if (first) + first = false; + else + oss << ", "; + oss << opt; + } + if (!m_hint.empty()) oss << " <" << m_hint << ">"; + return {{oss.str(), m_description}}; + } + + auto isMatch(std::string const& optToken) const -> bool { + auto normalisedToken = normaliseOpt(optToken); + for (auto const& name : m_optNames) { + if (normaliseOpt(name) == normalisedToken) return true; + } + return false; + } + + using ParserBase::parse; + + auto parse(std::string const&, TokenStream const& tokens) const + -> InternalParseResult override { + auto validationResult = validate(); + if (!validationResult) return InternalParseResult(validationResult); + + auto remainingTokens = tokens; + if (remainingTokens && remainingTokens->type == TokenType::Option) { + auto const& token = *remainingTokens; + if (isMatch(token.token)) { + if (m_ref->isFlag()) { + auto result = m_ref->setFlag(true); + if (!result) return InternalParseResult(result); + if (result.value() == ParseResultType::ShortCircuitAll) + return InternalParseResult::ok(ParseState(result.value(), remainingTokens)); + } else { + ++remainingTokens; + if (!remainingTokens) + return InternalParseResult::runtimeError("Expected argument following " + + token.token); + auto const& argToken = *remainingTokens; + if (argToken.type != TokenType::Argument) + return InternalParseResult::runtimeError("Expected argument following " + + token.token); + auto result = m_ref->setValue(argToken.token); + if (!result) return InternalParseResult(result); + if (result.value() == ParseResultType::ShortCircuitAll) + return InternalParseResult::ok(ParseState(result.value(), remainingTokens)); + } + return InternalParseResult::ok( + ParseState(ParseResultType::Matched, ++remainingTokens)); + } + } + return InternalParseResult::ok(ParseState(ParseResultType::NoMatch, remainingTokens)); + } + + auto validate() const -> Result override { + if (m_optNames.empty()) return Result::logicError("No options supplied to Opt"); + for (auto const& name : m_optNames) { + if (name.empty()) return Result::logicError("Option name cannot be empty"); +#ifdef CLARA_PLATFORM_WINDOWS + if (name[0] != '-' && name[0] != '/') + return Result::logicError("Option name must begin with '-' or '/'"); +#else + if (name[0] != '-') return Result::logicError("Option name must begin with '-'"); +#endif + } + return ParserRefImpl::validate(); + } +}; + +struct Help : Opt { + Help(bool& showHelpFlag) + : Opt([&](bool flag) { + showHelpFlag = flag; + return ParserResult::ok(ParseResultType::ShortCircuitAll); + }) { + static_cast (*this)("display usage information")["-?"]["-h"]["--help"].optional(); + } +}; + + +struct Parser : ParserBase { + mutable ExeName m_exeName; + std::vector m_options; + std::vector m_args; + + auto operator|=(ExeName const& exeName) -> Parser& { + m_exeName = exeName; + return *this; + } + + auto operator|=(Arg const& arg) -> Parser& { + m_args.push_back(arg); + return *this; + } + + auto operator|=(Opt const& opt) -> Parser& { + m_options.push_back(opt); + return *this; + } + + auto operator|=(Parser const& other) -> Parser& { + m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); + m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); + return *this; + } + + template + auto operator|(T const& other) const -> Parser { + return Parser(*this) |= other; + } + + auto getHelpColumns() const -> std::vector { + std::vector cols; + for (auto const& o : m_options) { + auto childCols = o.getHelpColumns(); + cols.insert(cols.end(), childCols.begin(), childCols.end()); + } + return cols; + } + + void writeToStream(std::ostream& os) const { + if (!m_exeName.name().empty()) { + os << "usage:\n" + << " " << m_exeName.name() << " "; + bool required = true, first = true; + for (auto const& arg : m_args) { + if (first) + first = false; + else + os << " "; + if (arg.isOptional() && required) { + os << "["; + required = false; + } + os << "<" << arg.hint() << ">"; + if (arg.cardinality() == 0) os << " ... "; + } + if (!required) os << "]"; + if (!m_options.empty()) os << " options"; + os << "\n\nwhere options are:" << std::endl; + } + + auto rows = getHelpColumns(); + size_t consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; + size_t optWidth = 0; + for (auto const& cols : rows) optWidth = (std::max)(optWidth, cols.left.size() + 2); + + for (auto const& cols : rows) { + auto row = TextFlow::Column(cols.left).width(optWidth).indent(2) + TextFlow::Spacer(4) + + TextFlow::Column(cols.right).width(consoleWidth - 7 - optWidth); + os << row << std::endl; + } + } + + friend auto operator<<(std::ostream& os, Parser const& parser) -> std::ostream& { + parser.writeToStream(os); + return os; + } + + auto validate() const -> Result override { + for (auto const& opt : m_options) { + auto result = opt.validate(); + if (!result) return result; + } + for (auto const& arg : m_args) { + auto result = arg.validate(); + if (!result) return result; + } + return Result::ok(); + } + + using ParserBase::parse; + + auto parse(std::string const& exeName, TokenStream const& tokens) const + -> InternalParseResult override { + struct ParserInfo { + ParserBase const* parser = nullptr; + size_t count = 0; + }; + const size_t totalParsers = m_options.size() + m_args.size(); + assert(totalParsers < 512); + // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do + ParserInfo parseInfos[512]; + + { + size_t i = 0; + for (auto const& opt : m_options) parseInfos[i++].parser = &opt; + for (auto const& arg : m_args) parseInfos[i++].parser = &arg; + } + + m_exeName.set(exeName); + + auto result = InternalParseResult::ok(ParseState(ParseResultType::NoMatch, tokens)); + while (result.value().remainingTokens()) { + bool tokenParsed = false; + + for (size_t i = 0; i < totalParsers; ++i) { + auto& parseInfo = parseInfos[i]; + if (parseInfo.parser->cardinality() == 0 || + parseInfo.count < parseInfo.parser->cardinality()) { + result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); + if (!result) return result; + if (result.value().type() != ParseResultType::NoMatch) { + tokenParsed = true; + ++parseInfo.count; + break; + } + } + } + + if (result.value().type() == ParseResultType::ShortCircuitAll) return result; + if (!tokenParsed) + return InternalParseResult::runtimeError("Unrecognised token: " + + result.value().remainingTokens()->token); + } + // !TBD Check missing required options + return result; + } +}; + +template +template +auto ComposableParserImpl::operator|(T const& other) const -> Parser { + return Parser() | static_cast(*this) | other; +} +} // namespace detail + + +// A Combined parser +using detail::Parser; + +// A parser for options +using detail::Opt; + +// A parser for arguments +using detail::Arg; + +// Wrapper for argc, argv from main() +using detail::Args; + +// Specifies the name of the executable +using detail::ExeName; + +// Convenience wrapper for option parser that specifies the help option +using detail::Help; + +// enum of result types from a parse +using detail::ParseResultType; + +// Result type for parser operation +using detail::ParserResult; + + +} // namespace clara + +#endif // CLARA_HPP_INCLUDED diff --git a/tests/src/deviceLib/hipAsynchronousStreams.cpp b/tests/src/deviceLib/hipAsynchronousStreams.cpp index 165c469941..2d15d33f1d 100644 --- a/tests/src/deviceLib/hipAsynchronousStreams.cpp +++ b/tests/src/deviceLib/hipAsynchronousStreams.cpp @@ -108,12 +108,12 @@ typedef struct { extern "C" __device__ __ockl_as_status_t __ockl_as_write_block(__ockl_as_stream_t ATTR_GLOBAL *stream, uchar service_id, - ulong *connection_id, const uchar *str, uint32_t len, + uint64_t *connection_id, const uchar *str, uint32_t len, uchar flags); __device__ __ockl_as_status_t __hip_as_write_block(__ockl_as_stream_t *stream, uchar service_id, - ulong *connection_id, const uchar *str, uint32_t len, + uint64_t *connection_id, const uchar *str, uint32_t len, uchar flags) { __ockl_as_stream_t ATTR_GLOBAL *gstream = diff --git a/tests/src/hipEnvVar.cpp b/tests/src/hipEnvVar.cpp index 2626e838dc..7c261b1fa3 100644 --- a/tests/src/hipEnvVar.cpp +++ b/tests/src/hipEnvVar.cpp @@ -27,57 +27,56 @@ THE SOFTWARE. #include #include -#include #include +#include "clara/clara.hpp" #include #include "hip/hip_runtime.h" +#ifdef _WIN64 +#include +#endif + +#ifdef _WIN64 +#define setenv(x,y,z) _putenv_s(x,y) +#endif + using namespace std; +using namespace clara; +inline clara::Parser cmdline_parser(bool& help, std::string& env, int &device, bool &retDevCnt) { + return clara::Opt{retDevCnt} + ["-c"] + ("total number of GPUs available") | -void usage() { - printf( - "hipEnvVar [otpions]\n\ - -c,\t\ttotal number of available GPUs and their pciBusID\n\ - -d,\t\tselect one GPU and return its pciBusID\n\ - -v,\t\tsend the list to HIP_VISIBLE_DEVICES env var\n\ - -h,\t\tshow this help message\n\ - "); + clara::Help{help} | + + clara::Opt{device,"device"} + ["-d"]["--device"] + ("select one GPU and return its pciBusID") | + + clara::Opt{env,"Set Env Value"} + ["-v"]["--EnvValue"] + ("send the list to HIP_VISIBLE_DEVICES env var, syntax -v="); } -int main(int argc, char** argv) { - // string str = getenv("HIP_VISIBLE_DEVICES"); - // std::cout << "The current env HIP_VISIBLE_DEVICES is"<= 0"< devCount - 1) { + if (device != INT_MAX && (device < 0 || device > devCount - 1)) { printf("Selected device %d is out of bound. Devices on your system are in range %d - %d\n", device, 0, devCount - 1); return -1; } if (retDevCnt) { - // std::cout << "Total number of devices visible in system is "<< devCount << std::endl; std::cout << devCount << std::endl; } - if (retDevInfo) { + if (device != INT_MAX) { hipDevice_t deviceT; hipDeviceGet(&deviceT, device); diff --git a/tests/src/hipEnvVarDriver.cpp b/tests/src/hipEnvVarDriver.cpp index 5063319ead..37e51faa31 100644 --- a/tests/src/hipEnvVarDriver.cpp +++ b/tests/src/hipEnvVarDriver.cpp @@ -30,6 +30,14 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include "hip/hip_runtime.h" #include #include + +#ifdef _WIN64 +#define popen(x,y) _popen(x,y) +#define pclose(x) _pclose(x) +#define setenv(x,y,z) _putenv_s(x,y) +#define unsetenv(x) _putenv_s(x,"") +#endif + using namespace std; int getDeviceNumber() { diff --git a/tests/src/kernel/hipLaunchParm.cpp b/tests/src/kernel/hipLaunchParm.cpp index 772ddc1032..23742d7d6c 100644 --- a/tests/src/kernel/hipLaunchParm.cpp +++ b/tests/src/kernel/hipLaunchParm.cpp @@ -577,16 +577,11 @@ __global__ void vAdd(float* a) {} // Some wrapper macro for testing: #define WRAP(...) __VA_ARGS__ -#include -#define GPU_PRINT_TIME(cmd, elapsed, quiet) \ +#define MY_LAUNCH_MACRO(cmd, elapsed, quiet) \ do { \ - struct timeval start, stop; \ - float elapsed; \ - gettimeofday(&start, NULL); \ hipDeviceSynchronize(); \ cmd; \ hipDeviceSynchronize(); \ - gettimeofday(&stop, NULL); \ } while (0); @@ -918,14 +913,14 @@ int main() { // Test: Passing hipLaunchKernelGGL inside another macro: float e0; - GPU_PRINT_TIME(hipLaunchKernelGGL(vAdd, dim3(1024), + MY_LAUNCH_MACRO(hipLaunchKernelGGL(vAdd, dim3(1024), dim3(1), 0, 0, Ad), e0, j); - GPU_PRINT_TIME(WRAP(hipLaunchKernelGGL(vAdd, dim3(1024), + MY_LAUNCH_MACRO(WRAP(hipLaunchKernelGGL(vAdd, dim3(1024), dim3(1), 0, 0, Ad)), e0, j); #ifdef EXTRA_PARENS_1 // Don't wrap hipLaunchKernelGGL in extra set of parens: - GPU_PRINT_TIME((hipLaunchKernelGGL(vAdd, dim3(1024), + MY_LAUNCH_MACRO((hipLaunchKernelGGL(vAdd, dim3(1024), dim3(1), 0, 0, Ad)), e0, j); #endif diff --git a/tests/src/runtimeApi/memory/hipMemcpy_simple.cpp b/tests/src/runtimeApi/memory/hipMemcpy_simple.cpp index 8ce02d6164..dcec1fd834 100644 --- a/tests/src/runtimeApi/memory/hipMemcpy_simple.cpp +++ b/tests/src/runtimeApi/memory/hipMemcpy_simple.cpp @@ -29,6 +29,9 @@ THE SOFTWARE. #include "hip/hip_runtime.h" #include "test_common.h" +#ifdef _WIN64 +#define aligned_alloc _aligned_malloc +#endif bool p_async = false; diff --git a/tests/src/runtimeApi/memory/hipMemoryAllocateCoherentDriver.cpp b/tests/src/runtimeApi/memory/hipMemoryAllocateCoherentDriver.cpp index f2f1e49c33..a064a6ad0a 100644 --- a/tests/src/runtimeApi/memory/hipMemoryAllocateCoherentDriver.cpp +++ b/tests/src/runtimeApi/memory/hipMemoryAllocateCoherentDriver.cpp @@ -29,6 +29,13 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include #include #include "hip/hip_runtime.h" + +#ifdef _WIN64 +#define popen(x,y) _popen(x,y) +#define pclose(x) _pclose(x) +#define setenv(x,y,z) _putenv_s(x,y) +#endif + using namespace std; string getRes() {