finish up custom string class implementation

This commit is contained in:
Thomas Fussell 2015-11-07 18:37:23 -05:00
parent 4919e7ea00
commit 7b5246f9dd
76 changed files with 807 additions and 502 deletions

View File

@ -29,7 +29,7 @@
#include <xlnt/cell/types.hpp> #include <xlnt/cell/types.hpp>
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {
@ -412,7 +412,7 @@ private:
/// </summary> /// </summary>
inline std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell) inline std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell)
{ {
return stream << cell.to_string(); return stream << std::string(cell.to_string().data());
} }
} // namespace xlnt } // namespace xlnt

View File

@ -28,7 +28,7 @@
#include <xlnt/cell/types.hpp> #include <xlnt/cell/types.hpp>
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -2,7 +2,7 @@
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -27,7 +27,7 @@
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
// We might want to change these types for various optimizations in the future // We might want to change these types for various optimizations in the future
// so use typedefs. // so use typedefs.

View File

@ -23,7 +23,7 @@
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -3,7 +3,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -27,7 +27,7 @@
#include <xlnt/utils/datetime.hpp> #include <xlnt/utils/datetime.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -4,7 +4,7 @@
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -8,7 +8,7 @@
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
// Note: this comes from https://github.com/tfussell/miniz-cpp // Note: this comes from https://github.com/tfussell/miniz-cpp

View File

@ -28,7 +28,7 @@
#include <xlnt/cell/comment.hpp> #include <xlnt/cell/comment.hpp>
#include <xlnt/worksheet/worksheet.hpp> #include <xlnt/worksheet/worksheet.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -30,7 +30,7 @@
#include <xlnt/packaging/zip_file.hpp> #include <xlnt/packaging/zip_file.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -2,7 +2,7 @@
#include <string> #include <string>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -4,7 +4,7 @@
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -27,7 +27,7 @@
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -29,7 +29,7 @@
#include <xlnt/workbook/workbook.hpp> #include <xlnt/workbook/workbook.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -25,7 +25,7 @@
#include <string> #include <string>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -26,7 +26,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -28,7 +28,7 @@
#include <xlnt/worksheet/worksheet.hpp> #include <xlnt/worksheet/worksheet.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -5,7 +5,7 @@
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {
namespace detail { struct xml_document_impl; } namespace detail { struct xml_document_impl; }

View File

@ -5,7 +5,7 @@
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {
namespace detail { struct xml_node_impl; } namespace detail { struct xml_node_impl; }

View File

@ -2,7 +2,7 @@
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -25,7 +25,7 @@
#include <xlnt/utils/hash_combine.hpp> #include <xlnt/utils/hash_combine.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -29,7 +29,7 @@
#include <xlnt/utils/hash_combine.hpp> #include <xlnt/utils/hash_combine.hpp>
#include <xlnt/styles/side.hpp> #include <xlnt/styles/side.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -26,7 +26,7 @@
#include <xlnt/utils/hash_combine.hpp> #include <xlnt/utils/hash_combine.hpp>
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -26,7 +26,7 @@
#include <xlnt/styles/color.hpp> #include <xlnt/styles/color.hpp>
#include <xlnt/utils/hash_combine.hpp> #include <xlnt/utils/hash_combine.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -28,7 +28,7 @@
#include <xlnt/utils/hash_combine.hpp> #include <xlnt/utils/hash_combine.hpp>
#include <xlnt/styles/color.hpp> #include <xlnt/styles/color.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -25,7 +25,7 @@
#include <xlnt/styles/style.hpp> #include <xlnt/styles/style.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -28,7 +28,7 @@
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -27,7 +27,7 @@
#include <xlnt/utils/hash_combine.hpp> #include <xlnt/utils/hash_combine.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -27,7 +27,7 @@
#include <xlnt/styles/color.hpp> #include <xlnt/styles/color.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -30,7 +30,7 @@
#include <xlnt/styles/number_format.hpp> #include <xlnt/styles/number_format.hpp>
#include <xlnt/styles/protection.hpp> #include <xlnt/styles/protection.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -24,7 +24,7 @@
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -27,7 +27,7 @@
#include <xlnt/cell/types.hpp> #include <xlnt/cell/types.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {
@ -48,7 +48,7 @@ class XLNT_CLASS cell_coordinates_exception
class XLNT_CLASS illegal_character_error class XLNT_CLASS illegal_character_error
{ {
public: public:
illegal_character_error(char c); illegal_character_error(utf32_char c);
}; };
/// <summary> /// <summary>

View File

@ -2,7 +2,7 @@
#include <functional> #include <functional>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -1,139 +1,87 @@
#pragma once #pragma once
#include <algorithm>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <iostream> #include <unordered_map>
#include <iterator>
#include <vector> #include <vector>
#include "xlnt_config.hpp" #ifdef XLNT_STD_STRING
#include <string>
#endif
#include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {
template<typename T>
class iter_range
{
public:
iter_range(T begin_iter, T end_iter) : begin_(begin_iter), end_(end_iter)
{
}
T begin() { return begin_; }
T end() { return end_; }
private:
T begin_;
T end_;
};
using utf_mb_narrow_char = char;
using utf_mb_narrow_string = utf_mb_narrow_char[];
using utf_mb_wide_char = wchar_t;
using utf_mb_wide_string = utf_mb_wide_char[];
using utf8_char = char;
using utf8_string = utf8_char[];
using utf16_char = char16_t;
using utf16_string = utf16_char[];
using utf32_char = char32_t;
using utf32_string = utf32_char[];
class XLNT_CLASS string class XLNT_CLASS string
{ {
public: public:
using value_type = std::uint32_t; using code_point = utf32_char;
using reference = value_type &; using reference = code_point &;
using const_reference = value_type &; using const_reference = const code_point &;
using pointer = value_type *; using pointer = code_point *;
using const_pointer = const pointer; using const_pointer = const code_point *;
using byte = char; using byte = char;
using byte_pointer = byte *; using byte_pointer = byte *;
using const_byte_pointer = const byte *; using const_byte_pointer = const byte *;
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
using size_type = std::size_t; using size_type = std::size_t;
using utf_mb_narrow_char = char; class const_iterator;
using utf_mb_narrow_string = utf_mb_narrow_char[];
using utf_mb_wide_char = wchar_t;
using utf_mb_wide_string = utf_mb_wide_char[];
using utf8_char = char;
using utf8_string = utf8_char[];
using utf16_char = char16_t;
using utf16_string = utf16_char[];
using utf32_char = char32_t;
using utf32_string = utf32_char[];
class code_point class iterator : public std::iterator<std::bidirectional_iterator_tag, code_point>
{ {
public: public:
code_point(byte_pointer data, size_type index, size_type end) iterator(string *parent, size_type index);
: data_(data),
index_(index),
end_(end)
{
}
code_point(const_byte_pointer data, size_type index, size_type end) iterator(const iterator &other);
: data_(const_cast<byte_pointer>(data)),
index_(index),
end_(end)
{
}
code_point &operator=(utf32_char value); code_point operator*();
code_point &operator=(const code_point &value) bool operator==(const iterator &other) const;
{
return *this = value.get();
}
bool operator==(char rhs) const; bool operator!=(const iterator &other) const { return !(*this == other); }
bool operator!=(char rhs) const;
bool operator<(char rhs) const;
bool operator<=(char rhs) const;
bool operator>(char rhs) const;
bool operator>=(char rhs) const;
utf32_char get() const; difference_type operator-(const iterator &other) const;
byte_pointer data_; iterator &operator+=(int offset) { return *this = *this + offset; }
size_type index_;
size_type end_;
};
template <bool is_const = true> iterator &operator-=(int offset) { return *this = *this - offset; }
class common_iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
{
public:
common_iterator(byte_pointer data, size_type index, size_type length)
: current_(data, index, length)
{
}
common_iterator(const_byte_pointer data, size_type index, size_type length) iterator operator+(int offset);
: current_(data, index, length)
{
}
common_iterator(const common_iterator<false> &other) iterator operator-(int offset) { return *this + (-1 * offset); }
: current_(other.current_)
{
}
common_iterator(const common_iterator<true> &other) iterator &operator--();
: current_(other.current_)
{
}
code_point &operator*() iterator operator--(int)
{
return current_;
}
bool operator==(const common_iterator &other) const
{
return current_.data_ == other.current_.data_ && current_.index_ == other.current_.index_;
}
bool operator!=(const common_iterator &other) const
{
return !(*this == other);
}
difference_type operator-(const common_iterator &other) const
{
return current_.index_ - other.current_.index_;
}
common_iterator operator+(size_type offset)
{
common_iterator copy = *this;
size_type end = std::max<size_type>(0, std::min<size_type>(current_.end_, current_.index_ + offset));
while (copy.current_.index_ != end)
{
end < copy.current_.index_ ? --copy : ++copy;
}
return copy;
}
common_iterator &operator--();
common_iterator operator--(int)
{ {
iterator old = *this; iterator old = *this;
--*this; --*this;
@ -141,40 +89,80 @@ public:
return old; return old;
} }
common_iterator &operator++(); iterator &operator++();
common_iterator operator++(int) iterator operator++(int)
{ {
common_iterator old = *this; iterator old = *this;
++*this; ++*this;
return old; return old;
} }
friend class common_iterator<true>;
private: private:
code_point current_; friend class const_iterator;
string *parent_;
size_type index_;
};
class const_iterator : public std::iterator<std::bidirectional_iterator_tag, code_point>
{
public:
const_iterator(const string *parent, size_type index);
const_iterator(const string::iterator &other);
const_iterator(const const_iterator &other);
const code_point operator*() const;
bool operator==(const const_iterator &other) const;
bool operator!=(const const_iterator &other) const { return !(*this == other); }
difference_type operator-(const const_iterator &other) const;
const_iterator &operator+=(int offset);
const_iterator &operator-=(int offset) { return *this += -offset; }
const_iterator operator+(int offset);
const_iterator operator-(int offset) { return *this + (-1 * offset); }
const_iterator &operator--();
const_iterator operator--(int)
{
const_iterator old = *this;
--*this;
return old;
}
const_iterator &operator++();
const_iterator operator++(int)
{
const_iterator old = *this;
++*this;
return old;
}
private:
const string *parent_;
size_type index_;
}; };
using iterator = common_iterator<false>;
using const_iterator = common_iterator<true>;
using reverse_iterator = std::reverse_iterator<iterator>; using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>;
static const size_type npos = -1; static const size_type npos = -1;
static string from(std::int8_t i); template<typename T>
static string from(std::int16_t i); static string from(T value);
static string from(std::int32_t i);
static string from(std::int64_t i);
static string from(std::uint8_t i);
static string from(std::uint16_t i);
static string from(std::uint32_t i);
static string from(std::uint64_t i);
static string from(float i);
static string from(double i);
static string from(long double i);
string(); string();
string(string &&str); string(string &&str);
@ -182,6 +170,10 @@ public:
string(const string &str, size_type offset); string(const string &str, size_type offset);
string(const string &str, size_type offset, size_type len); string(const string &str, size_type offset, size_type len);
#ifdef XLNT_STD_STRING
string(const std::string &str);
#endif
string(const utf_mb_wide_string str); string(const utf_mb_wide_string str);
string(const utf8_string str); string(const utf8_string str);
string(const utf16_string str); string(const utf16_string str);
@ -199,8 +191,8 @@ public:
~string(); ~string();
size_type length() const { return length_; } size_type length() const;
size_type bytes() const; size_type num_bytes() const;
bool empty() const { return length() == 0; } bool empty() const { return length() == 0; }
@ -210,35 +202,33 @@ public:
string substr(size_type offset) const; string substr(size_type offset) const;
string substr(size_type offset, size_type len) const; string substr(size_type offset, size_type len) const;
code_point back(); code_point back() const;
const code_point back() const; code_point front() const;
code_point front();
const code_point front() const;
size_type find(code_point c) const;
size_type find(char c) const; size_type find(char c) const;
size_type find(string str) const; size_type find(code_point c) const;
size_type find(const string &str) const;
size_type find(code_point c, size_type offset) const;
size_type find(char c, size_type offset) const; size_type find(char c, size_type offset) const;
size_type find(string str, size_type offset) const; size_type find(code_point c, size_type offset) const;
size_type find(const string &str, size_type offset) const;
size_type find_last_of(code_point c) const;
size_type find_last_of(char c) const; size_type find_last_of(char c) const;
size_type find_last_of(string str) const; size_type find_last_of(code_point c) const;
size_type find_last_of(const string &str) const;
size_type find_last_of(code_point c, size_type offset) const;
size_type find_last_of(char c, size_type offset) const; size_type find_last_of(char c, size_type offset) const;
size_type find_last_of(string str, size_type offset) const; size_type find_last_of(code_point c, size_type offset) const;
size_type find_last_of(const string &str, size_type offset) const;
size_type find_first_of(string str) const; size_type find_first_of(const string &str) const;
size_type find_first_of(string str, size_type offset) const; size_type find_first_of(const string &str, size_type offset) const;
size_type find_first_not_of(string str) const; size_type find_first_not_of(const string &str) const;
size_type find_first_not_of(string str, size_type offset) const; size_type find_first_not_of(const string &str, size_type offset) const;
size_type find_last_not_of(string str) const; size_type find_last_not_of(const string &str) const;
size_type find_last_not_of(string str, size_type offset) const; size_type find_last_not_of(const string &str, size_type offset) const;
void clear(); void clear();
@ -247,7 +237,7 @@ public:
int to_hex() const; int to_hex() const;
void remove(code_point iter); void erase(size_type index);
iterator begin(); iterator begin();
const_iterator begin() const { return cbegin(); } const_iterator begin() const { return cbegin(); }
@ -263,12 +253,13 @@ public:
string &operator=(string rhs); string &operator=(string rhs);
void append(char c); void append(utf_mb_narrow_char c);
void append(wchar_t c); void append(utf_mb_wide_char c);
void append(char16_t c); void append(utf16_char c);
void append(char32_t c);
void append(string str);
void append(code_point c); void append(code_point c);
void append(const string &str);
void replace(size_type index, utf32_char c);
code_point at(size_type index); code_point at(size_type index);
const code_point at(size_type index) const; const code_point at(size_type index) const;
@ -297,8 +288,8 @@ public:
private: private:
explicit string(size_type initial_size); explicit string(size_type initial_size);
size_type length_;
std::vector<byte> *data_; std::vector<byte> *data_;
std::unordered_map<size_type, size_type> *code_point_byte_offsets_;
}; };
} // namespace xlnt } // namespace xlnt

View File

@ -25,7 +25,7 @@
#include <string> #include <string>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -3,7 +3,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -31,7 +31,7 @@
#include <xlnt/packaging/relationship.hpp> #include <xlnt/packaging/relationship.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -7,7 +7,7 @@
#include <xlnt/worksheet/major_order.hpp> #include <xlnt/worksheet/major_order.hpp>
#include <xlnt/worksheet/worksheet.hpp> #include <xlnt/worksheet/worksheet.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -23,7 +23,7 @@
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -23,7 +23,7 @@
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -23,7 +23,7 @@
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -22,7 +22,7 @@
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -32,7 +32,7 @@
#include <xlnt/worksheet/range_reference.hpp> #include <xlnt/worksheet/range_reference.hpp>
#include <xlnt/worksheet/worksheet.hpp> #include <xlnt/worksheet/worksheet.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -24,7 +24,7 @@
#include <xlnt/cell/cell_reference.hpp> #include <xlnt/cell/cell_reference.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -23,7 +23,7 @@
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -22,7 +22,7 @@
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -2,7 +2,7 @@
#include <xlnt/utils/string.hpp> #include <xlnt/utils/string.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -22,7 +22,7 @@
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -33,7 +33,7 @@
#include <xlnt/packaging/relationship.hpp> #include <xlnt/packaging/relationship.hpp>
#include <xlnt/worksheet/page_setup.hpp> #include <xlnt/worksheet/page_setup.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -23,7 +23,7 @@
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once #pragma once
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -25,7 +25,7 @@
#include <string> #include <string>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
#include <xlnt/cell/cell.hpp> #include <xlnt/cell/cell.hpp>
#include <xlnt/cell/cell_reference.hpp> #include <xlnt/cell/cell_reference.hpp>

View File

@ -56,18 +56,25 @@ enum class limit_style
/// </summary> /// </summary>
const limit_style LimitStyle = limit_style::openpyxl; const limit_style LimitStyle = limit_style::openpyxl;
// If no API is defined, assume default #ifndef XLNT_API
#ifdef _MSC_VER #ifdef _MSC_VER
#if !defined(XLNT_API) && defined(SHARED) #ifdef XLNT_SHARED
#ifdef XLNT_EXPORT #ifdef XLNT_EXPORT
#define XLNT_API __declspec(dllexport) #define XLNT_API __declspec(dllexport)
#else #else
#define XLNT_API __declspec(dllimport) #define XLNT_API __declspec(dllimport)
#endif #endif // XLNT_EXPORT
#endif // XLNT_SHARED
#else #else
#define XLNT_API #define XLNT_API
#endif #endif // _MSC_VER
#endif #endif // XLNT_API
#ifndef XLNT_STD_STRING
#ifndef XLNT_SHARED
#define XLNT_STD_STRING
#endif // XLNT_SHARED
#endif // XLNT_STD_STRING
// If no API for classes is defined, assume default // If no API for classes is defined, assume default
#ifndef XLNT_CLASS #ifndef XLNT_CLASS

View File

@ -144,7 +144,7 @@ bool is_valid_color(const xlnt::string &color)
for (std::size_t i = 0; i < color.length(); i++) for (std::size_t i = 0; i < color.length(); i++)
{ {
if (std::toupper(color[i].get()) != std::toupper(other[i].get())) if (std::toupper(color[i]) != std::toupper(other[i]))
{ {
return false; return false;
} }
@ -335,7 +335,7 @@ bool is_valid_locale(const xlnt::string &locale_string)
for (auto c : country) for (auto c : country)
{ {
if (!is_hex(static_cast<char>(std::toupper(c.get())))) if (!is_hex(static_cast<char>(std::toupper(c))))
{ {
return false; return false;
} }
@ -699,12 +699,12 @@ xlnt::string format_section(long double number, const section &format, xlnt::cal
if (decimal_pos != xlnt::string::npos) if (decimal_pos != xlnt::string::npos)
{ {
result[decimal_pos] = ','; result.replace(decimal_pos, U',');
decimal_pos += 3; decimal_pos += 3;
while (decimal_pos < result.length()) while (decimal_pos < result.length())
{ {
result.remove(result.back()); result.erase(result.length());
} }
} }
} }
@ -1071,7 +1071,7 @@ bool cell::has_hyperlink() const
void cell::set_hyperlink(const string &hyperlink) void cell::set_hyperlink(const string &hyperlink)
{ {
if (hyperlink.length() == 0 || hyperlink.find(':') == std::string::npos) if (hyperlink.length() == 0 || hyperlink.find(':') == xlnt::string::npos)
{ {
throw data_type_exception(); throw data_type_exception();
} }

View File

@ -89,70 +89,52 @@ std::pair<string, row_t> cell_reference::split_reference(const string &reference
absolute_column = false; absolute_column = false;
absolute_row = false; absolute_row = false;
// Convert a coordinate string like 'B12' to a tuple ('B', 12) auto is_alpha = [](string::code_point c)
bool column_part = true; {
return (c >= U'A' && c <= U'Z') || (c >= U'a' && c <= U'z');
};
string column_string; auto upper_ref_string = reference_string.to_upper();
auto iter = upper_ref_string.begin();
auto end = upper_ref_string.end();
for (auto character : reference_string) while(iter != end && (is_alpha(*iter) || *iter == U'$'))
{ {
auto upper = std::toupper(character.get(), std::locale::classic()); ++iter;
if (std::isalpha(character.get(), std::locale::classic()))
{
if (column_part)
{
column_string.append(upper);
}
else
{
throw cell_coordinates_exception(reference_string);
}
}
else if (character == '$')
{
if (column_part)
{
if (column_string.empty())
{
column_string.append(upper);
}
else
{
column_part = false;
}
}
}
else
{
if (column_part)
{
column_part = false;
}
else if (!std::isdigit(character.get(), std::locale::classic()))
{
throw cell_coordinates_exception(reference_string);
}
}
} }
string row_string = reference_string.substr(column_string.length()); string column_string(upper_ref_string.begin(), iter);
if (row_string.length() == 0) if (column_string.length() > 1 && column_string.front() == '$')
{
throw cell_coordinates_exception(reference_string);
}
if (column_string[0] == '$')
{
absolute_row = true;
column_string = column_string.substr(1);
}
if (row_string[0] == '$')
{ {
absolute_column = true; absolute_column = true;
row_string = row_string.substr(1); column_string.erase(0);
}
if (column_string.length() > 1 && column_string.back() == '$')
{
absolute_row = true;
column_string.erase(column_string.length() - 1);
}
string row_string(iter, end);
auto is_digit = [](string::code_point c)
{
return (c >= U'0' && c <= U'9');
};
for(auto c : row_string)
{
if(!is_digit(c))
{
throw cell_coordinates_exception(reference_string);
}
}
if (column_string.length() == 0 || row_string.length() == 0)
{
throw cell_coordinates_exception(reference_string);
} }
return { column_string, row_string.to<row_t>() }; return { column_string, row_string.to<row_t>() };

View File

@ -257,7 +257,7 @@ public:
TS_ASSERT_THROWS(cell.set_value(str), xlnt::illegal_character_error); TS_ASSERT_THROWS(cell.set_value(str), xlnt::illegal_character_error);
} }
cell.set_value(xlnt::string("\33")); cell.set_value(xlnt::string("\41")); // !
cell.set_value(xlnt::string("\t")); // Tab cell.set_value(xlnt::string("\t")); // Tab
cell.set_value(xlnt::string("\n")); // Newline cell.set_value(xlnt::string("\n")); // Newline
cell.set_value(xlnt::string("\r")); // Carriage return cell.set_value(xlnt::string("\r")); // Carriage return
@ -361,7 +361,7 @@ public:
{ {
/* /*
unsigned char pound = 163; unsigned char pound = 163;
auto test_string = "Compount Value (" + std::string(pound) + ")"; auto test_string = "Compount Value (" + xlnt::string(pound) + ")";
auto ws = wb.create_sheet(); auto ws = wb.create_sheet();
cell = ws[xlnt::cell_reference("A1")]; cell = ws[xlnt::cell_reference("A1")];
TS_ASSERT_THROWS(cell.check_string(test_string), xlnt::unicode_decode_error); TS_ASSERT_THROWS(cell.check_string(test_string), xlnt::unicode_decode_error);

View File

@ -17,14 +17,23 @@ column_t::index_t column_t::column_index_from_string(const string &column_string
column_t::index_t column_index = 0; column_t::index_t column_index = 0;
int place = 1; int place = 1;
auto is_alpha = [](string::code_point c)
{
return (c >= U'A' && c <= U'Z') || (c >= U'a' && c <= U'z');
};
auto column_string_upper = column_string.to_upper();
for (int i = static_cast<int>(column_string.length()) - 1; i >= 0; i--) for (int i = static_cast<int>(column_string.length()) - 1; i >= 0; i--)
{ {
if (!std::isalpha(column_string[static_cast<std::size_t>(i)].get(), std::locale::classic())) auto index = static_cast<std::size_t>(i);
if (!is_alpha(column_string[index]))
{ {
throw column_string_index_exception(); throw column_string_index_exception();
} }
auto char_index = std::toupper(column_string[static_cast<std::size_t>(i)].get(), std::locale::classic()) - U'A'; auto char_index = column_string_upper[index] - U'A';
column_index += static_cast<column_t::index_t>((char_index + 1) * place); column_index += static_cast<column_t::index_t>((char_index + 1) * place);
place *= 26; place *= 26;

View File

@ -30,11 +30,11 @@ xlnt::string check_string(xlnt::string s)
s = s.substr(0, 32767); // max string length in Excel s = s.substr(0, 32767); // max string length in Excel
} }
for (xlnt::string::code_point c : s) for (auto c : s)
{ {
if (c >= 0 && (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31))) if (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31))
{ {
throw xlnt::illegal_character_error(0); throw xlnt::illegal_character_error(c);
} }
} }
@ -68,7 +68,49 @@ std::pair<bool, long double> cast_percentage(const xlnt::string &s)
std::pair<bool, xlnt::time> cast_time(const xlnt::string &s) std::pair<bool, xlnt::time> cast_time(const xlnt::string &s)
{ {
xlnt::time result; xlnt::time result;
try
{
auto last_colon = s.find_last_of(':');
if (last_colon == xlnt::string::npos)
{
return { false, result }; return { false, result };
}
double seconds = s.substr(last_colon + 1).to<double>();
result.second = static_cast<int>(seconds);
result.microsecond = static_cast<int>((seconds - static_cast<double>(result.second)) * 1e6);
auto first_colon = s.find(':');
if (first_colon == last_colon)
{
auto decimal_pos = s.find('.');
if (decimal_pos != xlnt::string::npos)
{
result.minute = s.substr(0, first_colon).to<int>();
}
else
{
result.hour = s.substr(0, first_colon).to<int>();
result.minute = result.second;
result.second = 0;
}
}
else
{
result.hour = s.substr(0, first_colon).to<int>();
result.minute = s.substr(first_colon + 1, last_colon - first_colon - 1).to<int>();
}
}
catch (std::invalid_argument)
{
return { false, result };
}
return { true, result };
} }
} // namespace } // namespace

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <xlnt/cell/comment.hpp> #include <xlnt/cell/comment.hpp>
#include <xlnt/utils/string.hpp>
namespace xlnt { namespace xlnt {
namespace detail { namespace detail {

View File

@ -2,7 +2,7 @@
#include <detail/constants.hpp> #include <detail/constants.hpp>
#include "xlnt_config.hpp" #include <xlnt/xlnt_config.hpp>
namespace xlnt { namespace xlnt {

View File

@ -289,7 +289,7 @@ void zip_file::append_comment()
auto comment_length = std::min(static_cast<uint16_t>(comment.length()), std::numeric_limits<uint16_t>::max()); auto comment_length = std::min(static_cast<uint16_t>(comment.length()), std::numeric_limits<uint16_t>::max());
buffer_[buffer_.size() - 2] = static_cast<char>(comment_length); buffer_[buffer_.size() - 2] = static_cast<char>(comment_length);
buffer_[buffer_.size() - 1] = static_cast<char>(comment_length >> 8); buffer_[buffer_.size() - 1] = static_cast<char>(comment_length >> 8);
std::copy(comment.data(), comment.data() + comment.bytes(), std::back_inserter(buffer_)); std::copy(comment.data(), comment.data() + comment.num_bytes(), std::back_inserter(buffer_));
} }
} }

View File

@ -225,7 +225,7 @@ xml_document workbook_serializer::write_workbook() const
sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/')); sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/'));
auto iter = sheet_index_string.end(); auto iter = sheet_index_string.end();
--iter; --iter;
while (isdigit((*iter).get())) while (isdigit(*iter))
--iter; --iter;
auto first_digit = iter - sheet_index_string.begin(); auto first_digit = iter - sheet_index_string.begin();
sheet_index_string = sheet_index_string.substr(static_cast<string::size_type>(first_digit + 1)); sheet_index_string = sheet_index_string.substr(static_cast<string::size_type>(first_digit + 1));

View File

@ -34,7 +34,7 @@ cell_coordinates_exception::cell_coordinates_exception(const string &coord_strin
{ {
} }
illegal_character_error::illegal_character_error(char c) illegal_character_error::illegal_character_error(xlnt::utf32_char c)
{ {
} }

View File

@ -1,8 +1,11 @@
#include <algorithm> #include <algorithm>
#include <array>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
//TODO: make this conditional on XLNT_STD_STRING once std::sto* functions are replaced
#include <string>
#include <vector> #include <vector>
#include <utf8.h> #include <utf8.h>
@ -12,7 +15,7 @@
namespace { namespace {
template<typename T> template<typename T>
std::size_t count_bytes(const T *arr) std::size_t string_length(const T *arr)
{ {
std::size_t i = 0; std::size_t i = 0;
@ -24,153 +27,229 @@ std::size_t count_bytes(const T *arr)
return i; return i;
} }
xlnt::string::code_point to_upper(xlnt::string::code_point p)
{
if(p >= U'a' && p <= U'z')
{
return U'A' + p - U'a';
}
return p;
}
xlnt::string::code_point to_lower(xlnt::string::code_point p)
{
if(p >= U'A' && p <= U'Z')
{
return U'a' + p - U'A';
}
return p;
}
} }
namespace xlnt { namespace xlnt {
bool string::code_point::operator==(char rhs) const template<>
{
return get() == rhs;
}
bool string::code_point::operator!=(char rhs) const
{
return get() != rhs;
}
bool string::code_point::operator<(char rhs) const
{
return char(get()) < rhs;
}
bool string::code_point::operator<=(char rhs) const
{
return char(get()) <= rhs;
}
bool string::code_point::operator>(char rhs) const
{
return char(get()) > rhs;
}
bool string::code_point::operator>=(char rhs) const
{
return char(get()) >= rhs;
}
string string::from(std::int8_t i) string string::from(std::int8_t i)
{ {
return string(std::to_string(i).c_str()); return string(std::to_string(i).c_str());
} }
template<>
string string::from(std::int16_t i) string string::from(std::int16_t i)
{ {
return string(std::to_string(i).c_str()); return string(std::to_string(i).c_str());
} }
template<>
string string::from(std::int32_t i) string string::from(std::int32_t i)
{ {
return string(std::to_string(i).c_str()); return string(std::to_string(i).c_str());
} }
template<>
string string::from(std::int64_t i) string string::from(std::int64_t i)
{ {
return string(std::to_string(i).c_str()); return string(std::to_string(i).c_str());
} }
template<>
string string::from(std::uint8_t i) string string::from(std::uint8_t i)
{ {
return string(std::to_string(i).c_str()); return string(std::to_string(i).c_str());
} }
template<>
string string::from(std::uint16_t i) string string::from(std::uint16_t i)
{ {
return string(std::to_string(i).c_str()); return string(std::to_string(i).c_str());
} }
template<>
string string::from(std::uint32_t i) string string::from(std::uint32_t i)
{ {
return string(std::to_string(i).c_str()); return string(std::to_string(i).c_str());
} }
template<>
string string::from(std::uint64_t i) string string::from(std::uint64_t i)
{ {
return string(std::to_string(i).c_str()); return string(std::to_string(i).c_str());
} }
template<>
string string::from(std::size_t i)
{
return string(std::to_string(i).c_str());
}
template<>
string string::from(float i) string string::from(float i)
{ {
return string(std::to_string(i).c_str()); return string(std::to_string(i).c_str());
} }
template<>
string string::from(double i) string string::from(double i)
{ {
return string(std::to_string(i).c_str()); return string(std::to_string(i).c_str());
} }
template<>
string string::from(long double i) string string::from(long double i)
{ {
return string(std::to_string(i).c_str()); return string(std::to_string(i).c_str());
} }
string::code_point &string::code_point::operator=(string::utf32_char value) #ifdef XLNT_STD_STRING
{
utf8::append(value, data_ + index_);
return *this;
}
string::utf32_char string::code_point::get() const
{
return utf8::peek_next(data_ + index_, data_ + end_);
}
template<> template<>
xlnt::string::common_iterator<false> &xlnt::string::common_iterator<false>::operator--() string string::from(const std::string &s)
{ {
auto iter = current_.data_ + current_.index_; return string(s.data());
utf8::prior(iter, current_.data_); }
current_.index_ = iter - current_.data_; #endif
xlnt::string::iterator::iterator(xlnt::string *parent, size_type index)
: parent_(parent),
index_(index)
{
}
xlnt::string::iterator::iterator(const xlnt::string::iterator &other)
: parent_(other.parent_),
index_(other.index_)
{
}
string::code_point xlnt::string::iterator::operator*()
{
return parent_->at(index_);
}
bool xlnt::string::iterator::operator==(const iterator &other) const
{
return parent_ == other.parent_ && index_ == other.index_;
}
string::difference_type string::iterator::operator-(const iterator &other) const
{
return index_ - other.index_;
}
xlnt::string::const_iterator::const_iterator(const xlnt::string *parent, size_type index)
: parent_(parent),
index_(index)
{
}
xlnt::string::const_iterator::const_iterator(const xlnt::string::iterator &other)
: parent_(other.parent_),
index_(other.index_)
{
}
xlnt::string::const_iterator::const_iterator(const xlnt::string::const_iterator &other)
: parent_(other.parent_),
index_(other.index_)
{
}
string::difference_type string::const_iterator::operator-(const const_iterator &other) const
{
return index_ - other.index_;
}
const string::code_point xlnt::string::const_iterator::operator*() const
{
return parent_->at(index_);
}
bool xlnt::string::const_iterator::operator==(const const_iterator &other) const
{
return parent_ == other.parent_ && index_ == other.index_;
}
xlnt::string::iterator &xlnt::string::iterator::operator--()
{
return *this -= 1;
}
xlnt::string::const_iterator &xlnt::string::const_iterator::operator--()
{
return *this -= 1;
}
xlnt::string::iterator &xlnt::string::iterator::operator++()
{
return *this += 1;
}
xlnt::string::const_iterator &xlnt::string::const_iterator::operator++()
{
return *this += 1;
}
string::const_iterator &string::const_iterator::operator+=(int offset)
{
auto new_index = index_ + offset;
new_index = std::max<int>(0, std::min<int>(parent_->length(), new_index));
index_ = static_cast<std::size_t>(new_index);
return *this; return *this;
} }
template<> xlnt::string::iterator xlnt::string::iterator::operator+(int offset)
xlnt::string::common_iterator<true> &xlnt::string::common_iterator<true>::operator--()
{ {
auto iter = current_.data_ + current_.index_; iterator copy = *this;
utf8::prior(iter, current_.data_);
current_.index_ = iter - current_.data_;
return *this; auto new_index = index_ + offset;
new_index = std::max<int>(0, std::min<int>(parent_->length(), new_index));
copy.index_ = static_cast<std::size_t>(new_index);
return copy;
} }
template<> xlnt::string::const_iterator xlnt::string::const_iterator::operator+(int offset)
xlnt::string::common_iterator<false> &xlnt::string::common_iterator<false>::operator++()
{ {
auto iter = current_.data_ + current_.index_; const_iterator copy = *this;
utf8::advance(iter, 1, current_.data_ + current_.end_);
current_.index_ = iter - current_.data_;
return *this; auto new_index = index_ + offset;
} new_index = std::max<int>(0, std::min<int>(parent_->length(), new_index));
copy.index_ = static_cast<std::size_t>(new_index);
template<> return copy;
xlnt::string::common_iterator<true> &xlnt::string::common_iterator<true>::operator++()
{
auto iter = current_.data_ + current_.index_;
utf8::advance(iter, 1, current_.data_ + current_.end_);
current_.index_ = iter - current_.data_;
return *this;
} }
string::string(size_type initial_size) string::string(size_type initial_size)
: length_(0), : data_(new std::vector<char>),
data_(new std::vector<char>) code_point_byte_offsets_(new std::unordered_map<size_type, size_type>)
{ {
data_->resize(initial_size + 1); data_->resize(initial_size + 1);
data_->back() = '\0'; data_->back() = '\0';
code_point_byte_offsets_->insert({0, 0});
} }
string::string() : string(size_type(0)) string::string() : string(size_type(0))
@ -182,7 +261,9 @@ string::string(string &&str) : string()
swap(*this, str); swap(*this, str);
} }
string::string(const string &str) : string(str, 0) string::string(const string &str)
: data_(new std::vector<char>(*str.data_)),
code_point_byte_offsets_(new std::unordered_map<size_type, size_type>(*str.code_point_byte_offsets_))
{ {
} }
@ -192,58 +273,100 @@ string::string(const string &str, size_type offset) : string(str, offset, str.le
string::string(const string &str, size_type offset, size_type len) : string() string::string(const string &str, size_type offset, size_type len) : string()
{ {
*this = str.substr(offset, len); auto part = str.substr(offset, len);
*data_ = *part.data_;
*code_point_byte_offsets_ = *part.code_point_byte_offsets_;
} }
#ifdef XLNT_STD_STRING
string::string(const std::string &str) : string(str.data())
{
}
#endif
string::string(const utf_mb_wide_string str) : string() string::string(const utf_mb_wide_string str) : string()
{ {
data_->clear(); auto iter = str;
utf8::utf16to8(str, str + count_bytes(str), std::back_inserter(*data_));
data_->push_back('\0');
length_ = utf8::distance(data(), data() + data_->size() - 1); while(*iter != '\0')
{
append(*iter);
iter++;
}
} }
string::string(const utf8_string str) : string() string::string(const utf8_string str) : string()
{ {
data_->clear(); auto start = str;
std::copy(str, str + count_bytes(str), std::back_inserter(*data_)); auto end = str;
data_->push_back('\0');
length_ = utf8::distance(data(), data() + data_->size() - 1); while(*end != '\0')
{
++end;
}
auto iter = start;
while(iter != end)
{
append((utf32_char)utf8::next(iter, end));
}
} }
string::string(const utf16_string str) : string() string::string(const utf16_string str) : string()
{ {
data_->clear(); auto iter = str;
utf8::utf16to8(str, str + count_bytes(str), std::back_inserter(*data_));
data_->push_back('\0');
length_ = utf8::distance(data(), data() + data_->size() - 1); while(*iter != '\0')
{
append(*iter);
iter++;
}
} }
string::string(const utf32_string str) : string() string::string(const utf32_string str) : string()
{ {
data_->clear(); auto iter = str;
utf8::utf32to8(str, str + count_bytes(str), std::back_inserter(*data_));
data_->push_back('\0');
length_ = utf8::distance(data(), data() + data_->size() - 1); while(*iter != '\0')
{
append(*iter);
iter++;
}
} }
string::~string() string::~string()
{ {
delete data_; delete data_;
data_ = nullptr;
delete code_point_byte_offsets_;
code_point_byte_offsets_ = nullptr;
} }
string string::to_upper() const string string::to_upper() const
{ {
return *this; string upper;
for(auto c : *this)
{
upper.append(::to_upper(c));
}
return upper;
} }
string string::to_lower() const string string::to_lower() const
{ {
return *this;
string lower;
for(auto c : *this)
{
lower.append(::to_lower(c));
}
return lower;
} }
string string::substr(size_type offset) const string string::substr(size_type offset) const
@ -253,37 +376,22 @@ string string::substr(size_type offset) const
string string::substr(size_type offset, size_type len) const string string::substr(size_type offset, size_type len) const
{ {
auto iter = begin() + offset; if(len != npos && offset + len < length())
size_type i = 0;
string result;
while (i++ < len && iter != end())
{ {
result.append(*iter); return string(begin() + offset, begin() + (offset + len));
++iter;
} }
return result; return string(begin() + offset, end());
} }
string::code_point string::back() string::code_point string::back() const
{ {
return *(begin() + length_ + -1); return at(length() - 1);
} }
const string::code_point string::back() const string::code_point string::front() const
{ {
return *(begin() + length_ + -1); return at(0);
}
string::code_point string::front()
{
return *begin();
}
const string::code_point string::front() const
{
return *begin();
} }
string::size_type string::find(code_point c) const string::size_type string::find(code_point c) const
@ -296,7 +404,7 @@ string::size_type string::find(char c) const
return find(c, 0); return find(c, 0);
} }
string::size_type string::find(string str) const string::size_type string::find(const string &str) const
{ {
return find(str, 0); return find(str, 0);
} }
@ -305,24 +413,6 @@ string::size_type string::find(code_point c, size_type offset) const
{ {
auto iter = begin() + offset; auto iter = begin() + offset;
while (iter != end())
{
if ((*iter).get() == c.get())
{
return offset;
}
++iter;
offset++;
}
return npos;
}
string::size_type string::find(char c, size_type offset) const
{
auto iter = begin() + offset;
while (iter != end()) while (iter != end())
{ {
if (*iter == c) if (*iter == c)
@ -337,9 +427,24 @@ string::size_type string::find(char c, size_type offset) const
return npos; return npos;
} }
string::size_type string::find(string str, size_type offset) const string::size_type string::find(char c, size_type offset) const
{ {
return 0; return find(static_cast<code_point>(c), offset);
}
string::size_type string::find(const string &str, size_type offset) const
{
while (offset < length() - str.length())
{
if (substr(offset, str.length()) == str)
{
return offset;
}
offset++;
}
return npos;
} }
string::size_type string::find_last_of(code_point c) const string::size_type string::find_last_of(code_point c) const
@ -352,60 +457,124 @@ string::size_type string::find_last_of(char c) const
return find_last_of(c, 0); return find_last_of(c, 0);
} }
string::size_type string::find_last_of(string str) const string::size_type string::find_last_of(const string &str) const
{ {
return find_last_of(str, 0); return find_last_of(str, 0);
} }
string::size_type string::find_last_of(code_point c, size_type offset) const string::size_type string::find_last_of(code_point c, size_type offset) const
{ {
return 0; auto stop = begin() + offset;
auto iter = end() - 1;
while (iter != stop)
{
if (*iter == c)
{
return iter - begin();
}
--iter;
}
return *stop == c ? offset : npos;
} }
string::size_type string::find_last_of(char c, size_type offset) const string::size_type string::find_last_of(char c, size_type offset) const
{ {
return 0; return find_last_of(static_cast<code_point>(c), offset);
} }
string::size_type string::find_last_of(string str, size_type offset) const string::size_type string::find_last_of(const string &str, size_type offset) const
{ {
return 0; auto stop = begin() + offset;
auto iter = end() - 1;
while (iter != stop)
{
if(str.find(*iter) != npos)
{
return iter - begin();
}
--iter;
}
return npos;
} }
string::size_type string::find_first_of(string str) const string::size_type string::find_first_of(const string &str) const
{ {
return find_first_of(str, 0); return find_first_of(str, 0);
} }
string::size_type string::find_first_of(string str, size_type offset) const string::size_type string::find_first_of(const string &str, size_type offset) const
{ {
return 0; auto iter = begin() + offset;
while (iter != end())
{
if(str.find(*iter) != npos)
{
return iter - begin();
}
++iter;
}
return npos;
} }
string::size_type string::find_first_not_of(string str) const string::size_type string::find_first_not_of(const string &str) const
{ {
return find_first_not_of(str, 0); return find_first_not_of(str, 0);
} }
string::size_type string::find_first_not_of(string str, size_type offset) const string::size_type string::find_first_not_of(const string &str, size_type offset) const
{ {
return 0; auto iter = begin() + offset;
while (iter != end())
{
if(str.find(*iter) == npos)
{
return iter - begin();
}
++iter;
}
return npos;
} }
string::size_type string::find_last_not_of(string str) const string::size_type string::find_last_not_of(const string &str) const
{ {
return find_last_not_of(str, 0); return find_last_not_of(str, 0);
} }
string::size_type string::find_last_not_of(string str, size_type offset) const string::size_type string::find_last_not_of(const string &str, size_type offset) const
{ {
return 0; auto stop = begin() + offset;
auto iter = end() - 1;
while (iter != stop)
{
if(str.find(*iter) == npos)
{
return iter - begin();
}
--iter;
}
return npos;
} }
void string::clear() void string::clear()
{ {
length_ = 0;
data_->clear(); data_->clear();
data_->push_back('\0'); data_->push_back('\0');
code_point_byte_offsets_->clear();
code_point_byte_offsets_->insert({0, 0});
} }
template<> template<>
@ -432,14 +601,40 @@ long double string::to() const
return std::stold(std::string(data())); return std::stold(std::string(data()));
} }
template<>
double string::to() const
{
return std::stod(std::string(data()));
}
#ifdef XLNT_STD_STRING
template<>
std::string string::to() const
{
return std::string(data());
}
#endif
int string::to_hex() const int string::to_hex() const
{ {
return 0; return 0;
} }
void string::remove(code_point iter) void string::erase(size_type index)
{ {
auto start = code_point_byte_offsets_->at(index);
auto next_start = code_point_byte_offsets_->at(index + 1);
data_->erase(data_->begin() + start, data_->begin() + next_start);
auto code_point_bytes = next_start - start;
for(size_type i = index + 1; i < length(); i++)
{
code_point_byte_offsets_->at(i) = code_point_byte_offsets_->at(i + 1) - code_point_bytes;
}
code_point_byte_offsets_->erase(code_point_byte_offsets_->find(length()));
} }
string &string::operator=(string rhs) string &string::operator=(string rhs)
@ -451,22 +646,22 @@ string &string::operator=(string rhs)
string::iterator string::begin() string::iterator string::begin()
{ {
return iterator(data(), 0, length_); return iterator(this, 0);
} }
string::const_iterator string::cbegin() const string::const_iterator string::cbegin() const
{ {
return const_iterator(data(), 0, length_); return const_iterator(this, 0);
} }
string::iterator string::end() string::iterator string::end()
{ {
return iterator(data(), length_, length_); return iterator(this, length());
} }
string::const_iterator string::cend() const string::const_iterator string::cend() const
{ {
return const_iterator(data(), length_, length_); return const_iterator(this, length());
} }
string::byte_pointer string::data() string::byte_pointer string::data()
@ -485,7 +680,7 @@ std::size_t string::hash() const
return hasher(std::string(data())); return hasher(std::string(data()));
} }
std::size_t string::bytes() const std::size_t string::num_bytes() const
{ {
return data_->size(); return data_->size();
} }
@ -495,37 +690,67 @@ void string::append(char c)
data_->back() = c; data_->back() = c;
data_->push_back('\0'); data_->push_back('\0');
length_++; code_point_byte_offsets_->insert({length() + 1, num_bytes() - 1});
} }
void string::append(wchar_t c) void string::append(wchar_t c)
{ {
if(c < 128)
{
append(static_cast<char>(c));
return;
}
data_->pop_back(); data_->pop_back();
utf8::utf16to8(&c, &c + 1, std::back_inserter(*data_));
std::array<char, 4> utf8_encoded {{0}};
auto end = utf8::utf16to8(&c, &c + 1, utf8_encoded.begin());
std::copy(utf8_encoded.begin(), end, std::back_inserter(*data_));
data_->push_back('\0'); data_->push_back('\0');
length_++; code_point_byte_offsets_->insert({length() + 1, num_bytes() - 1});
} }
void string::append(char16_t c) void string::append(char16_t c)
{ {
if(c < 128)
{
append(static_cast<char>(c));
return;
}
data_->pop_back(); data_->pop_back();
utf8::utf16to8(&c, &c + 1, std::back_inserter(*data_));
std::array<char, 4> utf8_encoded {{0}};
auto end = utf8::utf16to8(&c, &c + 1, utf8_encoded.begin());
std::copy(utf8_encoded.begin(), end, std::back_inserter(*data_));
data_->push_back('\0'); data_->push_back('\0');
length_++; code_point_byte_offsets_->insert({length() + 1, num_bytes() - 1});
} }
void string::append(char32_t c) void string::append(code_point c)
{ {
if(c < 128)
{
append(static_cast<char>(c));
return;
}
data_->pop_back(); data_->pop_back();
utf8::utf32to8(&c, &c + 1, std::back_inserter(*data_));
std::array<char, 4> utf8_encoded {{0}};
auto end = utf8::utf32to8(&c, &c + 1, utf8_encoded.begin());
std::copy(utf8_encoded.begin(), end, std::back_inserter(*data_));
data_->push_back('\0'); data_->push_back('\0');
length_++; code_point_byte_offsets_->insert({length() + 1, num_bytes() - 1});
} }
void string::append(string str) void string::append(const string &str)
{ {
for (auto c : str) for (auto c : str)
{ {
@ -533,19 +758,61 @@ void string::append(string str)
} }
} }
void string::append(code_point c) void string::replace(size_type index, utf32_char value)
{ {
append(c.get()); std::array<byte, 4> encoded = {{0}};
auto encoded_end = utf8::utf32to8(&value, &value + 1, encoded.begin());
auto encoded_len = encoded_end - encoded.begin();
auto data_start = code_point_byte_offsets_->at(index);
auto data_end = code_point_byte_offsets_->at(index + 1);
auto previous_len = data_end - data_start;
int difference = encoded_len - previous_len;
if(difference < 0)
{
data_->erase(data_->begin() + data_end + difference, data_->begin() + data_end);
}
else if(difference > 0)
{
data_->insert(data_->begin() + data_start, difference, '\0');
}
for(std::size_t i = index + 1; i < code_point_byte_offsets_->size(); i++)
{
code_point_byte_offsets_->at(i) += difference;
}
auto iter = encoded.begin();
auto data_iter = data_->begin() + data_start;
while(iter != encoded_end)
{
*data_iter = *iter;
++data_iter;
++iter;
}
} }
string::code_point string::at(size_type index) string::code_point string::at(size_type index)
{ {
return *(begin() + index); if(index == length())
{
return U'\0';
}
return utf8::peek_next(data_->begin() + code_point_byte_offsets_->at(index), data_->end());
} }
const string::code_point string::at(size_type index) const const string::code_point string::at(size_type index) const
{ {
return *(begin() + index); if(index == length())
{
return U'\0';
}
return utf8::peek_next(data_->begin() + code_point_byte_offsets_->at(index), data_->end());
} }
bool string::operator==(const_byte_pointer str) const bool string::operator==(const_byte_pointer str) const
@ -562,7 +829,7 @@ bool string::operator==(const string &str) const
while (left_iter != end() && right_iter != str.end()) while (left_iter != end() && right_iter != str.end())
{ {
if ((*left_iter).get() != (*right_iter).get()) if (*left_iter != *right_iter)
{ {
return false; return false;
} }
@ -603,8 +870,8 @@ void swap(string &left, string &right)
{ {
using std::swap; using std::swap;
swap(left.length_, right.length_);
swap(left.data_, right.data_); swap(left.data_, right.data_);
swap(left.code_point_byte_offsets_, right.code_point_byte_offsets_);
} }
std::ostream &operator<<(std::ostream &left, string &right) std::ostream &operator<<(std::ostream &left, string &right)
@ -631,4 +898,9 @@ bool string::operator<(const string &other) const
return std::string(data()) < std::string(other.data()); return std::string(data()) < std::string(other.data());
} }
string::size_type string::length() const
{
return code_point_byte_offsets_->size() - 1;
}
} // namespace xlnt } // namespace xlnt

View File

@ -27,7 +27,8 @@ std::vector<xlnt::string> split_string(const xlnt::string &string, char delim)
separator_index = string.find(delim, previous_index); separator_index = string.find(delim, previous_index);
} }
split.push_back(string.substr(previous_index)); auto part = string.substr(previous_index);
split.push_back(part);
return split; return split;
} }

View File

@ -47,9 +47,9 @@ public:
{ {
xlnt::workbook wb; xlnt::workbook wb;
auto new_sheet = wb.create_sheet(); auto new_sheet = wb.create_sheet();
std::string title = "my sheet"; xlnt::string title = "my sheet";
new_sheet.set_title(title.c_str()); new_sheet.set_title(title);
auto found_sheet = wb.get_sheet_by_name(title.c_str()); auto found_sheet = wb.get_sheet_by_name(title);
TS_ASSERT_EQUALS(new_sheet, found_sheet); TS_ASSERT_EQUALS(new_sheet, found_sheet);
} }
@ -120,9 +120,9 @@ public:
{ {
xlnt::workbook wb; xlnt::workbook wb;
auto new_sheet = wb.create_sheet(); auto new_sheet = wb.create_sheet();
std::string title = "my sheet"; xlnt::string title = "my sheet";
new_sheet.set_title(title.c_str()); new_sheet.set_title(title);
auto found_sheet = wb.get_sheet_by_name(title.c_str()); auto found_sheet = wb.get_sheet_by_name(title);
TS_ASSERT_EQUALS(new_sheet, found_sheet); TS_ASSERT_EQUALS(new_sheet, found_sheet);
} }

View File

@ -351,7 +351,7 @@ std::size_t workbook::index_from_ws_filename(const string &ws_filename)
sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/')); sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/'));
auto iter = sheet_index_string.end(); auto iter = sheet_index_string.end();
--iter; --iter;
while (isdigit((*iter).get())) while (isdigit((*iter)))
--iter; --iter;
auto first_digit = static_cast<std::size_t>(iter - sheet_index_string.begin()); auto first_digit = static_cast<std::size_t>(iter - sheet_index_string.begin());
sheet_index_string = sheet_index_string.substr(first_digit + 1); sheet_index_string = sheet_index_string.substr(first_digit + 1);
@ -388,9 +388,9 @@ worksheet workbook::create_sheet(const string &title)
throw sheet_title_exception(title); throw sheet_title_exception(title);
} }
if (std::find_if(title.data(), title.data() + title.bytes(), [](char c) { if (std::find_if(title.data(), title.data() + title.num_bytes(), [](char c) {
return c == '*' || c == ':' || c == '/' || c == '\\' || c == '?' || c == '[' || c == ']'; return c == '*' || c == ':' || c == '/' || c == '\\' || c == '?' || c == '[' || c == ']';
}) != title.data() + title.bytes()) }) != title.data() + title.num_bytes())
{ {
throw sheet_title_exception(title); throw sheet_title_exception(title);
} }

View File

@ -23,7 +23,7 @@ string sheet_protection::hash_password(const string &plaintext_password)
{ {
int password = 0x0000; int password = 0x0000;
for (int i = 1; i <= plaintext_password.bytes(); i++) for (int i = 1; i <= plaintext_password.num_bytes(); i++)
{ {
char character = plaintext_password.data()[i - 1]; char character = plaintext_password.data()[i - 1];
int value = character << i; int value = character << i;
@ -33,13 +33,13 @@ string sheet_protection::hash_password(const string &plaintext_password)
i++; i++;
} }
password ^= plaintext_password.bytes(); password ^= plaintext_password.num_bytes();
password ^= 0xCE4B; password ^= 0xCE4B;
string hashed = int_to_hex(password); string hashed = int_to_hex(password);
auto iter = hashed.data(); auto iter = hashed.data();
while (iter != hashed.data() + hashed.bytes()) while (iter != hashed.data() + hashed.num_bytes())
{ {
*iter = std::toupper(*iter, std::locale::classic()); *iter = std::toupper(*iter, std::locale::classic());
} }

View File

@ -55,13 +55,13 @@ public:
return compare_xml(expected_xml.get_root(), observed.get_root()); return compare_xml(expected_xml.get_root(), observed.get_root());
} }
static comparison_result compare_xml(const std::string &left_contents, const std::string &right_contents) static comparison_result compare_xml(const xlnt::string &left_contents, const xlnt::string &right_contents)
{ {
xlnt::xml_document left_xml; xlnt::xml_document left_xml;
left_xml.from_string(left_contents.c_str()); left_xml.from_string(left_contents.data());
xlnt::xml_document right_xml; xlnt::xml_document right_xml;
right_xml.from_string(right_contents.c_str()); right_xml.from_string(right_contents.data());
return compare_xml(left_xml.get_root(), right_xml.get_root()); return compare_xml(left_xml.get_root(), right_xml.get_root());
} }

View File

@ -62,7 +62,7 @@ public:
if (_NSGetExecutablePath(path.data(), &size) == 0) if (_NSGetExecutablePath(path.data(), &size) == 0)
{ {
return std::string(path.begin(), std::find(path.begin(), path.end(), '\0') - 9); return xlnt::string(path.begin(), std::find(path.begin(), path.end(), '\0') - 9);
} }
throw std::runtime_error("buffer too small, " + std::to_string(path.size()) + ", should be: " + std::to_string(size)); throw std::runtime_error("buffer too small, " + std::to_string(path.size()) + ", should be: " + std::to_string(size));
@ -126,7 +126,7 @@ public:
{ {
struct stat fileAtt; struct stat fileAtt;
if (stat(path.c_str(), &fileAtt) == 0) if (stat(path.data(), &fileAtt) == 0)
{ {
return S_ISREG(fileAtt.st_mode); return S_ISREG(fileAtt.st_mode);
} }

View File

@ -11,7 +11,7 @@
class TemporaryDirectory class TemporaryDirectory
{ {
public: public:
static std::string CreateTemporaryFilename() static xlnt::string CreateTemporaryFilename()
{ {
#ifdef _WIN32 #ifdef _WIN32
std::array<TCHAR, MAX_PATH> buffer; std::array<TCHAR, MAX_PATH> buffer;
@ -24,7 +24,7 @@ public:
{ {
throw std::runtime_error("GetTempPath failed"); throw std::runtime_error("GetTempPath failed");
} }
std::string directory(buffer.begin(), buffer.begin() + result); xlnt::string directory(buffer.begin(), buffer.begin() + result);
return PathHelper::WindowsToUniversalPath(directory + "xlnt"); return PathHelper::WindowsToUniversalPath(directory + "xlnt");
#else #else
return "/tmp/xlsx"; return "/tmp/xlsx";
@ -41,8 +41,8 @@ public:
remove(filename_.c_str()); remove(filename_.c_str());
} }
std::string GetFilename() const { return filename_; } xlnt::string GetFilename() const { return filename_; }
private: private:
const std::string filename_; const xlnt::string filename_;
}; };