Skip to content

iceoryx_utils/internal/cxx/convert.inl🔗

Namespaces🔗

Name
iox
building block to easily create free function for logging in a library context
iox::cxx

Defines🔗

Name
IOX_UTILS_CXX_CONVERT_INL

Macro Documentation🔗

define IOX_UTILS_CXX_CONVERT_INL🔗

#define IOX_UTILS_CXX_CONVERT_INL

Source code🔗

// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
#ifndef IOX_UTILS_CXX_CONVERT_INL
#define IOX_UTILS_CXX_CONVERT_INL

namespace iox
{
namespace cxx
{
template <typename Source>
inline typename std::enable_if<!std::is_convertible<Source, std::string>::value, std::string>::type
convert::toString(const Source& t)
{
    std::stringstream ss;
    ss << t;
    return ss.str();
}

template <typename Source>
inline typename std::enable_if<std::is_convertible<Source, std::string>::value, std::string>::type
convert::toString(const Source& t)
{
    return t;
}

template <typename Destination>
inline typename std::enable_if<std::is_convertible<const char*, Destination>::value, bool>::type
fromString(const char* v, Destination& dest)
{
    dest = Destination(v);
    return true;
}

template <>
inline bool convert::fromString<std::string>(const char* v, std::string& dest)
{
    dest = std::string(v);
    return true;
}

template <>
inline bool convert::fromString<char>(const char* v, char& dest)
{
    if (strlen(v) != 1u)
    {
        std::cerr << v << " is not a char" << std::endl;
        return false;
    }
    dest = v[0];
    return true;
}

template <>
inline bool convert::fromString<string<100>>(const char* v, string<100>& dest)
{
    dest = string<100>(TruncateToCapacity, v);
    return true;
}

inline bool convert::stringIsNumber(const char* v, const NumberType type)
{
    if (v[0] == '\0')
        return false;

    bool hasDot = false;

    for (uint32_t i = 0u; v[i] != '\0'; ++i)
    {
        if (v[i] >= 48 && v[i] <= 57) // 48 == ascii 0, 57 == ascii 9
        {
            continue;
        }
        else if (type != NumberType::UNSIGNED_INTEGER && i == 0u
                 && (v[i] == 43 || v[i] == 45)) // 43 == ascii +, 45 == ascii -
        {
            continue;
        }
        else if (type == NumberType::FLOAT && !hasDot && v[i] == 46) // 46 == ascii .
        {
            hasDot = true;
        }
        else
        {
            return false;
        }
    }

    return true;
}

inline bool convert::stringIsNumberWithErrorMessage(const char* v, const NumberType type)
{
    if (!stringIsNumber(v, type))
    {
        std::cerr << v << " is not ";
        switch (type)
        {
        case NumberType::FLOAT:
        {
            std::cerr << "a float";
            break;
        }
        case NumberType::INTEGER:
        {
            std::cerr << "a signed integer";
            break;
        }
        case NumberType::UNSIGNED_INTEGER:
        {
            std::cerr << "an unsigned integer";
            break;
        }
        }
        std::cerr << std::endl;
        return false;
    }
    return true;
}

template <>
inline bool convert::fromString<float>(const char* v, float& dest)
{
    if (!stringIsNumberWithErrorMessage(v, NumberType::FLOAT))
    {
        return false;
    }

    auto call = makeSmartC(strtof, ReturnMode::PRE_DEFINED_ERROR_CODE, {HUGE_VALF, -HUGE_VALF}, {}, v, nullptr);

    if (call.hasErrors())
    {
        return false;
    }

    dest = call.getReturnValue();
    return true;
}

template <>
inline bool convert::fromString<double>(const char* v, double& dest)
{
    if (!stringIsNumberWithErrorMessage(v, NumberType::FLOAT))
    {
        return false;
    }

    auto call = makeSmartC(strtod, ReturnMode::PRE_DEFINED_ERROR_CODE, {HUGE_VAL, -HUGE_VAL}, {}, v, nullptr);

    if (call.hasErrors())
    {
        return false;
    }

    dest = call.getReturnValue();
    return true;
}

template <>
inline bool convert::fromString<long double>(const char* v, long double& dest)
{
    if (!stringIsNumberWithErrorMessage(v, NumberType::FLOAT))
    {
        return false;
    }

    auto call = makeSmartC(strtold, ReturnMode::PRE_DEFINED_ERROR_CODE, {HUGE_VALL, -HUGE_VALL}, {}, v, nullptr);

    if (call.hasErrors())
    {
        return false;
    }

    dest = call.getReturnValue();
    return true;
}

template <>
inline bool convert::fromString<uint64_t>(const char* v, uint64_t& dest)
{
    if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER))
    {
        return false;
    }

    auto call = makeSmartC(strtoull, ReturnMode::PRE_DEFINED_ERROR_CODE, {ULLONG_MAX}, {}, v, nullptr, STRTOULL_BASE);
    if (call.hasErrors())
    {
        return false;
    }

    if (call.getReturnValue() > std::numeric_limits<uint64_t>::max())
    {
        std::cerr << call.getReturnValue() << " too large, uint64_t overflow" << std::endl;
        return false;
    }

    dest = static_cast<uint64_t>(call.getReturnValue());
    return true;
}

#ifdef __APPLE__
template <>
inline bool convert::fromString<unsigned long>(const char* v, unsigned long& dest)
{
    uint64_t temp{0};
    bool retVal = fromString(v, temp);
    dest = temp;
    return retVal;
}
#endif

template <>
inline bool convert::fromString<uint32_t>(const char* v, uint32_t& dest)
{
    if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER))
    {
        return false;
    }

    auto call = makeSmartC(strtoull, ReturnMode::PRE_DEFINED_ERROR_CODE, {ULLONG_MAX}, {}, v, nullptr, STRTOULL_BASE);
    if (call.hasErrors())
    {
        return false;
    }

    if (call.getReturnValue() > std::numeric_limits<uint32_t>::max())
    {
        std::cerr << call.getReturnValue() << " too large, uint32_t overflow" << std::endl;
        return false;
    }

    dest = static_cast<uint32_t>(call.getReturnValue());
    return true;
}

template <>
inline bool convert::fromString<uint16_t>(const char* v, uint16_t& dest)
{
    if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER))
    {
        return false;
    }

    auto call = makeSmartC(strtoul, ReturnMode::PRE_DEFINED_ERROR_CODE, {ULONG_MAX}, {}, v, nullptr, 10);
    if (call.hasErrors())
    {
        return false;
    }

    if (call.getReturnValue() > std::numeric_limits<uint16_t>::max())
    {
        std::cerr << call.getReturnValue() << " too large, uint16_t overflow" << std::endl;
        return false;
    }

    dest = static_cast<uint16_t>(call.getReturnValue());
    return true;
}

template <>
inline bool convert::fromString<uint8_t>(const char* v, uint8_t& dest)
{
    if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER))
    {
        return false;
    }

    auto call = makeSmartC(strtoul, ReturnMode::PRE_DEFINED_ERROR_CODE, {ULONG_MAX}, {}, v, nullptr, 10);
    if (call.hasErrors())
    {
        return false;
    }

    if (call.getReturnValue() > std::numeric_limits<uint8_t>::max())
    {
        std::cerr << call.getReturnValue() << " too large, uint8_t overflow" << std::endl;
        return false;
    }

    dest = static_cast<uint8_t>(call.getReturnValue());
    return true;
}

template <>
inline bool convert::fromString<int64_t>(const char* v, int64_t& dest)
{
    if (!stringIsNumberWithErrorMessage(v, NumberType::INTEGER))
    {
        return false;
    }

    auto call = makeSmartC(strtoll, ReturnMode::PRE_DEFINED_ERROR_CODE, {LLONG_MAX, LLONG_MIN}, {}, v, nullptr, 10);
    if (call.hasErrors())
    {
        return false;
    }

    if (call.getReturnValue() > std::numeric_limits<int64_t>::max()
        || call.getReturnValue() < std::numeric_limits<int64_t>::min())
    {
        std::cerr << call.getReturnValue() << " is out of range, int64_t overflow" << std::endl;
        return false;
    }

    dest = static_cast<int64_t>(call.getReturnValue());
    return true;
}

template <>
inline bool convert::fromString<int32_t>(const char* v, int32_t& dest)
{
    if (!stringIsNumberWithErrorMessage(v, NumberType::INTEGER))
    {
        return false;
    }

    auto call = makeSmartC(strtoll, ReturnMode::PRE_DEFINED_ERROR_CODE, {LLONG_MAX, LLONG_MIN}, {}, v, nullptr, 10);
    if (call.hasErrors())
    {
        return false;
    }

    if (call.getReturnValue() > std::numeric_limits<int32_t>::max()
        || call.getReturnValue() < std::numeric_limits<int32_t>::min())
    {
        std::cerr << call.getReturnValue() << " is out of range, int32_t overflow" << std::endl;
        return false;
    }

    dest = static_cast<int32_t>(call.getReturnValue());
    return true;
}

template <>
inline bool convert::fromString<int16_t>(const char* v, int16_t& dest)
{
    if (!stringIsNumberWithErrorMessage(v, NumberType::INTEGER))
    {
        return false;
    }

    auto call = makeSmartC(strtol, ReturnMode::PRE_DEFINED_ERROR_CODE, {LONG_MAX, LONG_MIN}, {}, v, nullptr, 10);
    if (call.hasErrors())
    {
        return false;
    }

    if (call.getReturnValue() > std::numeric_limits<int16_t>::max()
        || call.getReturnValue() < std::numeric_limits<int16_t>::min())
    {
        std::cerr << call.getReturnValue() << " is out of range, int16_t overflow" << std::endl;
        return false;
    }

    dest = static_cast<int16_t>(call.getReturnValue());
    return true;
}

template <>
inline bool convert::fromString<int8_t>(const char* v, int8_t& dest)
{
    if (!stringIsNumberWithErrorMessage(v, NumberType::INTEGER))
    {
        return false;
    }

    auto call = makeSmartC(strtol, ReturnMode::PRE_DEFINED_ERROR_CODE, {LONG_MAX, LONG_MIN}, {}, v, nullptr, 10);
    if (call.hasErrors())
    {
        return false;
    }

    if (call.getReturnValue() > std::numeric_limits<int8_t>::max()
        || call.getReturnValue() < std::numeric_limits<int8_t>::min())
    {
        std::cerr << call.getReturnValue() << " is out of range, int8_t overflow" << std::endl;
        return false;
    }

    dest = static_cast<int8_t>(call.getReturnValue());
    return true;
}

template <>
inline bool convert::fromString<bool>(const char* v, bool& dest)
{
    if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER))
    {
        return false;
    }

    auto call = makeSmartC(strtoul, ReturnMode::PRE_DEFINED_ERROR_CODE, {ULONG_MAX}, {}, v, nullptr, 10);
    if (call.hasErrors())
    {
        return false;
    }

    dest = static_cast<bool>(call.getReturnValue());
    return true;
}

} // namespace cxx
} // namespace iox

#endif // IOX_UTILS_CXX_CONVERT_INL

Updated on 31 May 2022 at 15:29:15 CEST