Add new compose() method using variadic templates.
authorCarl Hetherington <cth@carlh.net>
Fri, 9 Jul 2021 22:45:47 +0000 (00:45 +0200)
committerCarl Hetherington <cth@carlh.net>
Fri, 9 Jul 2021 23:17:22 +0000 (01:17 +0200)
src/compose.cc [new file with mode: 0644]
src/compose.hpp
src/wscript

diff --git a/src/compose.cc b/src/compose.cc
new file mode 100644 (file)
index 0000000..95898b5
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+    Copyright (C) 2021 Carl Hetherington <cth@carlh.net>
+
+    This file is part of libdcp.
+
+    libdcp is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    libdcp is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with libdcp.  If not, see <http://www.gnu.org/licenses/>.
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of portions of this program with the
+    OpenSSL library under certain conditions as described in each
+    individual source file, and distribute linked combinations
+    including the two.
+
+    You must obey the GNU General Public License in all respects
+    for all of the code used other than OpenSSL.  If you modify
+    file(s) with this exception, you may extend this exception to your
+    version of the file(s), but you are not obligated to do so.  If you
+    do not wish to do so, delete this exception statement from your
+    version.  If you delete this exception statement from all source
+    files in the program, then also delete it here.
+*/
+
+
+#include "compose.hpp"
+
+
+void
+dcp::collect(std::vector<std::string>&)
+{
+
+}
+
+
index 41a4075a86e4d3f5419d90bf5bb7034dc34f476d..a7bc115464404241c5169d29f0b96159f541f579 100644 (file)
-/* -*- c-basic-offset: 2 -*-
- * Defines String::compose(fmt, arg...) for easy, i18n-friendly
- * composition of strings.
- *
- * Version 1.0.
- *
- * Copyright (c) 2002 Ole Laursen <olau@hardworking.dk>.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA.
- */
+/*
+    Copyright (C) 2021 Carl Hetherington <cth@carlh.net>
 
-//
-// Basic usage is like
-//
-//   std::cout << String::compose("This is a %1x%2 matrix.", rows, cols);
-//
-// See http://www.cs.aau.dk/~olau/compose/ or the included README.compose for
-// more details.
-//
+    This file is part of libdcp.
 
-#ifndef STRING_COMPOSE_H
-#define STRING_COMPOSE_H
+    libdcp is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
 
-#include "locale_convert.h"
-#include <boost/filesystem.hpp>
-#include <string>
-#include <list>
-#include <map>
-#include <inttypes.h>
-#include <cstdio>
+    libdcp is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
 
-namespace dcp {
-
-namespace StringPrivate
-{
-  // the actual composition class - using string::compose is cleaner, so we
-  // hide it here
-  class Composition
-  {
-  public:
-    // initialize and prepare format string on the form "text %1 text %2 etc."
-    explicit Composition(std::string fmt);
+    You should have received a copy of the GNU General Public License
+    along with libdcp.  If not, see <http://www.gnu.org/licenses/>.
 
-    // supply an replacement argument starting from %1
-    template <typename T>
-    Composition &arg(const T &obj);
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of portions of this program with the
+    OpenSSL library under certain conditions as described in each
+    individual source file, and distribute linked combinations
+    including the two.
 
-    // compose and return string
-    std::string str() const;
+    You must obey the GNU General Public License in all respects
+    for all of the code used other than OpenSSL.  If you modify
+    file(s) with this exception, you may extend this exception to your
+    version of the file(s), but you are not obligated to do so.  If you
+    do not wish to do so, delete this exception statement from your
+    version.  If you delete this exception statement from all source
+    files in the program, then also delete it here.
+*/
 
-  private:
-    std::string os;
-    int arg_no;
 
-    // we store the output as a list - when the output string is requested, the
-    // list is concatenated to a string; this way we can keep iterators into
-    // the list instead of into a string where they're possibly invalidated on
-    // inserting a specification string
-    typedef std::list<std::string> output_list;
-    output_list output;
+#ifndef LIBDCP_STRING_H
+#define LIBDCP_STRING_H
 
-    // the initial parse of the format string fills in the specification map
-    // with positions for each of the various %?s
-    typedef std::multimap<int, output_list::iterator> specification_map;
-    specification_map specs;
-  };
 
-  // helper for converting spec string numbers
-  inline int char_to_int(char c)
-  {
-    switch (c) {
-    case '0': return 0;
-    case '1': return 1;
-    case '2': return 2;
-    case '3': return 3;
-    case '4': return 4;
-    case '5': return 5;
-    case '6': return 6;
-    case '7': return 7;
-    case '8': return 8;
-    case '9': return 9;
-    default: return -1000;
-    }
-  }
-
-  inline bool is_number(int n)
-  {
-    switch (n) {
-    case '0':
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-    case '8':
-    case '9':
-      return true;
-
-    default:
-      return false;
-    }
-  }
-
-  // implementation of class Composition
-  template <typename T>
-  inline Composition &Composition::arg(const T &obj)
-  {
-    os += dcp::locale_convert<std::string> (obj);
+#include "dcp_assert.h"
+#include "locale_convert.h"
+#include <boost/algorithm/string.hpp>
+#include <string>
+#include <vector>
 
-    if (!os.empty()) {         // manipulators don't produce output
-      for (specification_map::const_iterator i = specs.lower_bound(arg_no), end = specs.upper_bound(arg_no); i != end; ++i) {
-       output_list::iterator pos = i->second;
-       ++pos;
 
-       output.insert(pos, os);
-      }
+namespace dcp {
 
-      os = "";
-      ++arg_no;
-    }
 
-    return *this;
-  }
+void collect(std::vector<std::string>&);
 
-  inline Composition::Composition(std::string fmt)
-    : arg_no(1)
-  {
-    std::string::size_type b = 0, i = 0;
 
-    // fill in output with the strings between the %1 %2 %3 etc. and
-    // fill in specs with the positions
-    while (i < fmt.length()) {
-      if (fmt[i] == '%' && i + 1 < fmt.length()) {
-       if (fmt[i + 1] == '%') {        // catch %%
-         fmt.replace(i, 2, "%");
-         ++i;
+template <typename T, typename ...Ts>
+void collect(std::vector<std::string>& string_args, T arg, Ts... rest)
+{
+       auto const string_arg = locale_convert<std::string>(arg);
+       if (!string_arg.empty()) {
+               string_args.push_back(string_arg);
        }
-       else if (is_number(fmt[i + 1])) { // aha! a spec!
-         // save string
-         output.push_back(fmt.substr(b, i - b));
-
-         int n = 1;            // number of digits
-         int spec_no = 0;
+       collect(string_args, rest...);
+}
 
-         do {
-           spec_no += char_to_int(fmt[i + n]);
-           spec_no *= 10;
-           ++n;
-         } while (i + n < fmt.length() && is_number(fmt[i + n]));
 
-         spec_no /= 10;
-         output_list::iterator pos = output.end();
-         --pos;                // safe since we have just inserted a string>
+namespace String {
 
-         specs.insert(specification_map::value_type(spec_no, pos));
 
-         // jump over spec string
-         i += n;
-         b = i;
+template <typename...Ts>
+std::string compose(std::string fmt, Ts... args)
+{
+       std::vector<std::string> string_args;
+       collect(string_args, args...);
+       for (auto i = 0U; i < 10; ++i) {
+               std::string place = "%";
+               place += static_cast<char>(49 + i);
+               std::string value = i < string_args.size() ? string_args[i] : "";
+               boost::algorithm::replace_all(fmt, place, value);
        }
-       else
-         ++i;
-      }
-      else
-       ++i;
-    }
-
-    if (i - b > 0)             // add the rest of the string
-      output.push_back(fmt.substr(b, i - b));
-  }
-
-  inline std::string Composition::str() const
-  {
-    // assemble string
-    std::string str;
-
-    for (output_list::const_iterator i = output.begin(), end = output.end();
-        i != end; ++i)
-      str += *i;
-
-    return str;
-  }
+       boost::algorithm::replace_all(fmt, "%%", "%");
+       return fmt;
 }
 
-// now for the real thing(s)
-namespace String
-{
-  // a series of functions which accept a format string on the form "text %1
-  // more %2 less %3" and a number of templated parameters and spits out the
-  // composited string
-  template <typename T1>
-  inline std::string compose(const std::string &fmt, const T1 &o1)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1);
-    return c.str();
-  }
-
-  template <typename T1, typename T2>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2);
-    return c.str();
-  }
-
-  template <typename T1, typename T2, typename T3>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2, const T3 &o3)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2).arg(o3);
-    return c.str();
-  }
-
-  template <typename T1, typename T2, typename T3, typename T4>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2, const T3 &o3,
-                            const T4 &o4)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2).arg(o3).arg(o4);
-    return c.str();
-  }
-
-  template <typename T1, typename T2, typename T3, typename T4, typename T5>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2, const T3 &o3,
-                            const T4 &o4, const T5 &o5)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
-    return c.str();
-  }
-
-  template <typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2, const T3 &o3,
-                            const T4 &o4, const T5 &o5, const T6 &o6)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
-    return c.str();
-  }
-
-  template <typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6, typename T7>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2, const T3 &o3,
-                            const T4 &o4, const T5 &o5, const T6 &o6,
-                            const T7 &o7)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
-    return c.str();
-  }
 
-  template <typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6, typename T7, typename T8>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2, const T3 &o3,
-                            const T4 &o4, const T5 &o5, const T6 &o6,
-                            const T7 &o7, const T8 &o8)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
-    return c.str();
-  }
-
-  template <typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6, typename T7, typename T8, typename T9>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2, const T3 &o3,
-                            const T4 &o4, const T5 &o5, const T6 &o6,
-                            const T7 &o7, const T8 &o8, const T9 &o9)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
-    return c.str();
-  }
-
-  template <typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6, typename T7, typename T8, typename T9, typename T10>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2, const T3 &o3,
-                            const T4 &o4, const T5 &o5, const T6 &o6,
-                            const T7 &o7, const T8 &o8, const T9 &o9,
-                            const T10 &o10)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
-      .arg(o10);
-    return c.str();
-  }
-
-  template <typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6, typename T7, typename T8, typename T9, typename T10,
-           typename T11>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2, const T3 &o3,
-                            const T4 &o4, const T5 &o5, const T6 &o6,
-                            const T7 &o7, const T8 &o8, const T9 &o9,
-                            const T10 &o10, const T11 &o11)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
-      .arg(o10).arg(o11);
-    return c.str();
-  }
-
-  template <typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6, typename T7, typename T8, typename T9, typename T10,
-           typename T11, typename T12>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2, const T3 &o3,
-                            const T4 &o4, const T5 &o5, const T6 &o6,
-                            const T7 &o7, const T8 &o8, const T9 &o9,
-                            const T10 &o10, const T11 &o11, const T12 &o12)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
-      .arg(o10).arg(o11).arg(o12);
-    return c.str();
-  }
-
-  template <typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6, typename T7, typename T8, typename T9, typename T10,
-           typename T11, typename T12, typename T13>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2, const T3 &o3,
-                            const T4 &o4, const T5 &o5, const T6 &o6,
-                            const T7 &o7, const T8 &o8, const T9 &o9,
-                            const T10 &o10, const T11 &o11, const T12 &o12,
-                            const T13 &o13)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
-      .arg(o10).arg(o11).arg(o12).arg(o13);
-    return c.str();
-  }
+}
 
-  template <typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6, typename T7, typename T8, typename T9, typename T10,
-           typename T11, typename T12, typename T13, typename T14>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2, const T3 &o3,
-                            const T4 &o4, const T5 &o5, const T6 &o6,
-                            const T7 &o7, const T8 &o8, const T9 &o9,
-                            const T10 &o10, const T11 &o11, const T12 &o12,
-                            const T13 &o13, const T14 &o14)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
-      .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
-    return c.str();
-  }
 
-  template <typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6, typename T7, typename T8, typename T9, typename T10,
-           typename T11, typename T12, typename T13, typename T14,
-           typename T15>
-  inline std::string compose(const std::string &fmt,
-                            const T1 &o1, const T2 &o2, const T3 &o3,
-                            const T4 &o4, const T5 &o5, const T6 &o6,
-                            const T7 &o7, const T8 &o8, const T9 &o9,
-                            const T10 &o10, const T11 &o11, const T12 &o12,
-                            const T13 &o13, const T14 &o14, const T15 &o15)
-  {
-    StringPrivate::Composition c(fmt);
-    c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
-      .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
-    return c.str();
-  }
 }
 
-}
 
-#endif // STRING_COMPOSE_H
+#endif
+
index 4108265a512d9db75457c7796edde0a0bf6f5503..9f102a970edc486fc578e36e363e2a5ee54b0d68 100644 (file)
@@ -46,6 +46,7 @@ def build(bld):
              chromaticity.cc
              colour_conversion.cc
              combine.cc
+             compose.cc
              cpl.cc
              data.cc
              dcp.cc