--- /dev/null
+#include <config.h>
+
+#include "../trivstring.h"
+
+#include <iostream>
+
+
+using namespace lyx;
+
+using namespace std;
+
+void test_trivstring()
+{
+ string const input[] = {
+ "",
+ "a",
+ "42",
+ "max sso", // max. string with sso on 64 bit
+ "something which does not fit into sso"
+ };
+ size_t const n = sizeof(input) / sizeof(input[0]);
+ for (size_t i = 0; i < n; ++i) {
+ // construction from std::string
+ trivstring const a(input[i]);
+ // construction from trivstring
+ trivstring const b(a);
+ // assignment from trivstring
+ trivstring const c = a;
+ // assignment from std::string
+ trivstring const d = input[i];
+ // assignment from trivstring
+ string const e = a.str();
+ // assignment from trivstring via C string
+ string const f = a.c_str();
+ cout << a.length() << endl;
+ cout << a.str() << endl;
+ cout << b.str() << endl;
+ cout << c.str() << endl;
+ cout << d.str() << endl;
+ cout << e << endl;
+ cout << f << endl;
+ }
+}
+
+int main()
+{
+ test_trivstring();
+}
--- /dev/null
+0
+
+
+
+
+
+
+1
+a
+a
+a
+a
+a
+a
+2
+42
+42
+42
+42
+42
+42
+7
+max sso
+max sso
+max sso
+max sso
+max sso
+max sso
+37
+something which does not fit into sso
+something which does not fit into sso
+something which does not fit into sso
+something which does not fit into sso
+something which does not fit into sso
+something which does not fit into sso
--- /dev/null
+#!/bin/sh
+
+regfile=`cat ${srcdir}/tests/regfiles/trivstring`
+output=`./check_trivstring`
+
+test "$regfile" = "$output"
+exit $?
--- /dev/null
+/**
+ * \file trivstring.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Georg Baum
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "support/trivstring.h"
+#include "support/docstring.h"
+
+#include <algorithm>
+
+using namespace std;
+
+namespace lyx {
+
+template trivial_string<char>::trivial_string(trivial_string const &);
+template trivial_string<char_type>::trivial_string(trivial_string const &);
+template<typename Char>
+trivial_string<Char>::trivial_string(trivial_string const & that) : size_(that.size_)
+{
+ if (use_sso())
+ copy(that.data_sso(), that.data_sso() + size_ + 1, data_sso());
+ else if (size_ > 0) {
+ data_ = new Char[size_ + 1];
+ copy(that.data_, that.data_ + size_ + 1, data_);
+ }
+ // else Happens only for really big Char types
+}
+
+
+template trivial_string<char>::trivial_string(string const &);
+template trivial_string<char_type>::trivial_string(docstring const &);
+template<typename Char>
+trivial_string<Char>::trivial_string(
+ basic_string<Char, char_traits<Char>, allocator<Char> > const & that)
+ : size_(that.length())
+{
+ if (use_sso()) {
+ copy(that.begin(), that.end(), data_sso());
+ data_sso()[size_] = '\0';
+ } else if (size_ > 0) {
+ data_ = new Char[size_ + 1];
+ copy(that.begin(), that.end(), data_);
+ data_[size_] = '\0';
+ }
+ // else Happens only for really big Char types
+}
+
+
+template trivial_string<char> &
+trivial_string<char>::operator=(trivial_string const &);
+template trivial_string<char_type> &
+trivial_string<char_type>::operator=(trivial_string const &);
+template<typename Char>
+trivial_string<Char> & trivial_string<Char>::operator=(trivial_string const & that)
+{
+ if (&that == this)
+ return *this;
+ if (!use_sso())
+ delete[] data_;
+ size_ = that.size_;
+ if (use_sso())
+ copy(that.data_sso(), that.data_sso() + size_ + 1, data_sso());
+ else if (size_ > 0) {
+ data_ = new Char[size_ + 1];
+ copy(that.data_, that.data_ + size_ + 1, data_);
+ } else {
+ // Happens only for really big Char types
+ data_ = 0;
+ }
+ return *this;
+}
+
+
+template trivial_string<char> &
+trivial_string<char>::operator=(string const &);
+template trivial_string<char_type> &
+trivial_string<char_type>::operator=(docstring const &);
+template<typename Char>
+trivial_string<Char> &
+trivial_string<Char>::operator=(basic_string<Char, char_traits<Char>, allocator<Char> > const & that)
+{
+ if (!use_sso())
+ delete[] data_;
+ size_ = that.size();
+ if (use_sso()) {
+ copy(that.begin(), that.end(), data_sso());
+ data_sso()[size_] = '\0';
+ } else if (size_ > 0) {
+ data_ = new Char[size_ + 1];
+ copy(that.begin(), that.end(), data_);
+ } else {
+ // Happens only for really big Char types
+ data_ = 0;
+ }
+ return *this;
+}
+
+
+template void
+trivial_string<char>::swap(trivial_string<char> &);
+template void
+trivial_string<char_type>::swap(trivial_string<char_type> &);
+template<typename Char>
+void trivial_string<Char>::swap(trivial_string & that)
+{
+ size_t const sizetmp = that.size_;
+ that.size_ = size_;
+ size_ = sizetmp;
+ Char * const datatmp = that.data_;
+ that.data_ = data_;
+ data_ = datatmp;
+}
+
+
+template<typename Char>
+int trivial_string<Char>::compare(trivial_string const & other) const
+{
+ size_t const lsize = this->length();
+ size_t const rsize = other.length();
+ size_t const len = min(lsize, rsize);
+ int r = char_traits<Char>::compare(c_str(), other.c_str(), len);
+ if (r == 0) {
+ if (lsize > rsize)
+ r = 1;
+ else if (lsize < rsize)
+ r = -1;
+ }
+ return r;
+}
+
+
+template string trivial_string<char>::str() const;
+template docstring trivial_string<char_type>::str() const;
+template<typename Char>
+basic_string<Char, char_traits<Char>, allocator<Char> >
+trivial_string<Char>::str() const
+{
+ if (use_sso())
+ return basic_string<Char, char_traits<Char>, allocator<Char> >(
+ data_sso(), size_);
+ if (size_ > 0)
+ return basic_string<Char, char_traits<Char>, allocator<Char> >(
+ data_, size_);
+ // Happens only for really big Char types
+ return basic_string<Char, char_traits<Char>, allocator<Char> >();
+}
+
+
+template char const * trivial_string<char>::c_str() const;
+template char_type const * trivial_string<char_type>::c_str() const;
+template<typename Char> Char const * trivial_string<Char>::c_str() const
+{
+ if (use_sso())
+ return data_sso();
+ if (size_ > 0)
+ return data_;
+ // Happens only for really big Char types
+ static const Char empty_char = '\0';
+ return &empty_char;
+}
+
+
+template bool operator<(trivial_string<char> const &,
+ trivial_string<char> const &);
+template bool operator<(trivial_string<char_type> const &,
+ trivial_string<char_type> const &);
+template <typename Char>
+bool operator<(trivial_string<Char> const & lhs, trivial_string<Char> const &rhs)
+{
+ return lhs.compare(rhs) < 0;
+}
+
+} // namespace lyx
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file trivstring.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Georg Baum
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef LYX_TRIVSTRING_H
+#define LYX_TRIVSTRING_H
+
+#include "support/strfwd.h"
+
+#include <cstdlib>
+
+namespace lyx {
+
+/**
+ * Trivial string class with almost no features.
+ * The public interface is a subset of the std::basic_string interface.
+ * The only important feature is that any read-only access does not need
+ * synchronization between multiple threads, i.e. it is thread-safe without
+ * locking.
+ * Therefore you can safely use a const trivial_string object in multiple
+ * threads at the same time. This is not the case for std::basic_string in some
+ * STL implementations (e. g. GNU libcstd++, see bug 9336 and
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=21334.
+ * This class should not be used for anything else than providing thread-safety.
+ * It should be removed as soon as LyX requires C++11, and all supported STL
+ * implementations provide a C++11 conformant std::basic_string.
+ */
+template <typename Char> class trivial_string
+{
+public:
+ /// Construct an empty string
+ trivial_string() : size_(0), data_(0) {}
+ /// Construct a string from a copy of \p that
+ trivial_string(trivial_string const & that);
+ /// Construct a string from a copy of \p that
+ trivial_string(std::basic_string<Char, std::char_traits<Char>, std::allocator<Char> > const & that);
+ ///
+ ~trivial_string() { if (!use_sso()) delete[] data_; }
+ /// Assign a copy of \p that
+ trivial_string & operator=(trivial_string const & that);
+ /// Assign a copy of \p that
+ trivial_string & operator=(std::basic_string<Char, std::char_traits<Char>, std::allocator<Char> > const & that);
+ /// Exchange contents with contents of \p that
+ void swap(trivial_string & that);
+ /// The length of the string, excluding the final 0 character
+ size_t length() const { return size_; }
+ /// Is this string empty?
+ bool empty() const { return size_ == 0; }
+ /// Is this string ordered before, at the same position or after \p other?
+ int compare(trivial_string const & other) const;
+ /// Create a copy as std::basic_string
+ std::basic_string<Char, std::char_traits<Char>, std::allocator<Char> > str() const;
+ /// Return a C-compatible string, terminated by a 0 character.
+ /// This is never a copy and only valid for the life time of the trivial_string instance.
+ Char const * c_str() const;
+private:
+ /**
+ * Whether short string optimization is used.
+ * Short string optimization is a technique where no additional memory
+ * needs to be allocated to store the string contents.
+ * Instead, the memory which would be used to store the pointer to the
+ * character buffer is reinterpreted to be a Char * buffer.
+ * On most 64 bit systems and with Char == char this allows to store
+ * strings of up to 7 characters without allocating additional memory.
+ */
+ bool use_sso() const { return (size_ + 1) * sizeof(Char) <= sizeof(Char *); }
+ /// The character storage if sso is used
+ Char * data_sso() { return reinterpret_cast<Char * >(&data_); }
+ /// The character storage if sso is used
+ Char const * data_sso() const { return reinterpret_cast<Char const *>(&data_); }
+ /// The length of the string, excluding the final 0 character
+ size_t size_;
+ /// The character storage
+ Char * data_;
+};
+template <typename Char> bool operator<(trivial_string<Char> const & lhs, trivial_string<Char> const &rhs);
+
+
+} // namespace lyx
+#endif