Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Introduce constexpr #39

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ if (BUILD_TESTING)
test/*.hpp
)
add_executable(testing ${testing_src} include/json.hpp)

file(GLOB testing20_src
test20/*.cpp
test20/*.h
test20/*.hpp
)
add_executable(testing20 ${testing20_src} include/json.hpp)
set_target_properties(testing20
PROPERTIES
CXX_STANDARD 20
)
endif()

if (BUILD_BENCHMARK)
Expand Down
163 changes: 163 additions & 0 deletions include/constexpr_helper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
#pragma once

#include <string>

#include "constexpr_map.hpp"
#include "constexpr_unique_ptr.hpp"
#include "constexpr_variant.hpp"

namespace json
{

namespace soft_impl
{

constexpr int to_string_double_precision = 14;

template <typename elem_t>
constexpr bool is_digit(elem_t ch)
{
return '0' <= ch && ch <= '9';
}

template <typename string_t>
constexpr string_t to_string(unsigned long long value)
{
string_t result;
do {
result.push_back('0' + value % 10);
value /= 10;
} while (value > 0);
return string_t(result.rbegin(), result.rend());
}

template <typename string_t>
constexpr string_t to_string(long long value)
{
string_t result;
bool nega = false;
if (value == INT64_MIN) {
return to_string<string_t>(0x8000000000000000ull);
}
if (value < 0) {
nega = true;
value = -value;
}
do {
result.push_back('0' + value % 10);
value /= 10;
} while (value > 0);
if (nega) {
result.push_back('-');
}
return string_t(result.rbegin(), result.rend());
}

template <typename string_t>
constexpr string_t to_string(double value)
{
string_t result;
if (value < 0) {
result.push_back('-');
value = -value;
}
int precision = to_string_double_precision;
double base = 1;
int log_base = 0;
while (base <= value) {
base *= 10;
log_base++;
}
if (log_base == 0) {
while (base > value) {
base /= 10;
log_base--;
}
log_base++;
base *= 10;

result.push_back('0');
result.push_back('.');
for (int k = 0; k > log_base; k--) {
result.push_back('0');
}
}
while (precision--) {
log_base--;
base /= 10;
char c = '0';
while (value >= base) {
value -= base;
c++;
}
result.push_back(c);
if (log_base == 0) {
result.push_back('.');
}
}
if (log_base > 0) {
while (log_base > 0) {
result.push_back('0');
log_base--;
}
result.push_back('.');
}
return result;
}

template <typename string_t>
constexpr string_t to_string(signed char v)
{
return to_string<string_t>(static_cast<long long>(v));
}
template <typename string_t>
constexpr string_t to_string(short v)
{
return to_string<string_t>(static_cast<long long>(v));
}
template <typename string_t>
constexpr string_t to_string(int v)
{
return to_string<string_t>(static_cast<long long>(v));
}
template <typename string_t>
constexpr string_t to_string(long v)
{
return to_string<string_t>(static_cast<long long>(v));
}

template <typename string_t>
constexpr string_t to_string(unsigned char v)
{
return to_string<string_t>(static_cast<unsigned long long>(v));
}
template <typename string_t>
constexpr string_t to_string(unsigned short v)
{
return to_string<string_t>(static_cast<unsigned long long>(v));
}
template <typename string_t>
constexpr string_t to_string(unsigned int v)
{
return to_string<string_t>(static_cast<unsigned long long>(v));
}
template <typename string_t>
constexpr string_t to_string(unsigned long v)
{
return to_string<string_t>(static_cast<unsigned long long>(v));
}

template <typename string_t>
constexpr string_t to_string(float v)
{
return to_string<string_t>(static_cast<double>(v));
}
template <typename string_t>
constexpr string_t to_string(long double v)
{
return to_string<string_t>(static_cast<double>(v));
}

} // namespace soft_impl

}; // namespace json
184 changes: 184 additions & 0 deletions include/constexpr_map.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#pragma once

#include <utility>
#include <vector>

namespace json
{

template <typename Iter, typename Val, typename Pred>
inline constexpr Iter lower_bound_fix(Iter begin, Iter end, const Val& val, Pred pred)
{
#ifdef __GLIBCXX__
// lower_bound实现的有问题
// https://github.com/gcc-mirror/gcc/blob/d9375e490072d1aae73a93949aa158fcd2a27018/libstdc%2B%2B-v3/include/bits/stl_algobase.h#L1023
return std::__lower_bound(begin, end, val, [&pred](auto iter, const auto& val) { return pred(*iter, val); });
#else
return std::lower_bound(begin, end, val, pred);
#endif
}

template <typename key_t, typename value_t>
class constexpr_map
{
using container_type = std::vector<std::pair<key_t, value_t>>;

public:
using key_type = key_t;
using mapped_type = value_t;
using value_type = typename container_type::value_type;

struct iterator
{
typename container_type::iterator _iter;

using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename container_type::iterator::value_type;
using difference_type = typename container_type::iterator::difference_type;
using pointer = typename container_type::iterator::pointer;
using reference = typename container_type::iterator::reference;

constexpr iterator(typename container_type::iterator&& it) : _iter(it) {}

constexpr iterator& operator++()
{
++_iter;
return *this;
}

constexpr iterator operator++(int) { return iterator { _iter++ }; }

constexpr iterator& operator--()
{
--_iter;
return *this;
}

constexpr iterator operator--(int) { return iterator { _iter-- }; }

constexpr value_type& operator*() const { return *_iter; }

constexpr value_type* operator->() const { return &*_iter; }

friend constexpr bool operator==(const iterator& x, const iterator& y) { return x._iter == y._iter; }

friend constexpr bool operator!=(const iterator& x, const iterator& y) { return x._iter != y._iter; }
};

struct const_iterator
{
typename container_type::const_iterator _iter;

using value_type = typename container_type::const_iterator::value_type;
using difference_type = typename container_type::const_iterator::difference_type;
using pointer = typename container_type::const_iterator::pointer;
using reference = typename container_type::const_iterator::reference;

constexpr const_iterator(typename container_type::const_iterator&& it) : _iter(it) {}

constexpr const_iterator& operator++()
{
++_iter;
return *this;
}

constexpr const_iterator operator++(int) { return const_iterator { _iter++ }; }

constexpr const_iterator& operator--()
{
--_iter;
return *this;
}

constexpr const_iterator operator--(int) { return const_iterator { _iter-- }; }

constexpr const value_type& operator*() const { return *_iter; }

constexpr const value_type* operator->() const { return &*_iter; }

friend constexpr bool operator==(const const_iterator& x, const const_iterator& y)
{
return x._iter == y._iter;
}

friend constexpr bool operator!=(const const_iterator& x, const const_iterator& y)
{
return x._iter != y._iter;
}
};

constexpr constexpr_map() = default;
constexpr constexpr_map(const constexpr_map&) = default;
constexpr constexpr_map(constexpr_map&&) = default;
constexpr ~constexpr_map() = default;
constexpr constexpr_map& operator=(const constexpr_map&) = default;
constexpr constexpr_map& operator=(constexpr_map&&) = default;

template <typename... Args>
constexpr constexpr_map(Args&&... args) : _data(args...)
{}

constexpr iterator begin() { return _data.begin(); }

constexpr const_iterator begin() const { return _data.begin(); }

constexpr const_iterator cbegin() const { return _data.cbegin(); }

constexpr iterator end() { return _data.end(); }

constexpr const_iterator end() const { return _data.end(); }

constexpr const_iterator cend() const { return _data.cend(); }

constexpr mapped_type& operator[](const key_t& key) { return emplace(key, mapped_type {}).first->second; }

constexpr mapped_type& operator[](key_t&& key)
{
return emplace(std::forward<key_t&&>(key), mapped_type {}).first->second;
}

constexpr iterator find(const key_t& key)
{
auto ptr = lower_bound_fix(begin(), end(), key,
[](const value_type& elem, const key_type& val) { return elem.first < val; });
return ptr->first == key ? ptr : end();
}

constexpr const_iterator find(const key_t& key) const
{
auto ptr = lower_bound_fix(cbegin(), cend(), key,
[](const value_type& elem, const key_type& val) { return elem.first < val; });
return ptr->first == key ? ptr : cend();
}

template <typename... Args>
constexpr std::pair<iterator, bool> emplace(Args&&... args)
{
value_type p(std::forward<Args&&>(args)...);
auto ptr = lower_bound_fix(begin(), end(), p.first,
[](const value_type& elem, const key_type& val) { return elem.first < val; });
if (ptr != end() && ptr->first == p.first) {
return std::make_pair(ptr, false);
}
else {
return std::make_pair(_data.insert(ptr._iter, std::move(p)), true);
}
}

private:
container_type _data;
};

} // namespace json

template <typename key_t, typename value_t>
constexpr bool operator==(const json::constexpr_map<key_t, value_t>& x, const json::constexpr_map<key_t, value_t>& y)
{
return x._data == y._data;
}

template <typename key_t, typename value_t>
constexpr bool operator!=(const json::constexpr_map<key_t, value_t>& x, const json::constexpr_map<key_t, value_t>& y)
{
return !(x == y);
}
Loading
Loading