Как создать простую библиотеку std :: string-to-boost :: posix_time :: ptime

Я недавно обнаружил необходимость разбора std::string к boost::posix_time::ptime, На вопрос о том, как выполнить эту задачу, можно найти хороший ответ здесь: Как разобрать дату / время из строки?.

Я знаю, что для этого требуется всего несколько строк кода (в основном, это объявление istringstream, неявность locale / time_input_facet и извлечение в ptime), но я хотел обернуть эту функциональность в удобную функцию и сделать ее доступной в виде библиотеки C ++ для моих различных программ. которые работают с ptimes.

Если возможно, я хотел бы получить отзывы от гуру C ++ о моем дизайне, просто чтобы я мог знать, сделал ли я что-то явно не так или есть лучшие подходы там. В частности, я не очень знаком с тем, как работают locales и time_input_facets, поэтому я надеюсь, что у меня нет утечки памяти или чего-либо еще.

Вот:

namespace mydt {

void imbueDTFormat(std::istringstream& iss, const std::string& format );
void parse(const std::string& input, const std::string& format, boost::posix_time::ptime& out ); // (1)
void parse(const std::string& input, std::istringstream& iss, boost::posix_time::ptime& out ); // (2)
void parse(std::istringstream& iss, boost::posix_time::ptime& out ); // (3)

void imbueDTFormat(std::istringstream& iss, const std::string& format ) {
iss.imbue(std::locale(std::locale::classic(), new boost::posix_time::time_input_facet(format) )); // see <http://en.cppreference.com/w/cpp/locale/locale/locale>: "Overload 7 is typically called with its second argument, f, obtained directly from a new-expression: the locale is responsible for calling the matching delete from its own destructor."} // end imbueDTFormat()

void parse(const std::string& input, const std::string& format, boost::posix_time::ptime& out ) { // (1)
static std::istringstream iss;
imbueDTFormat(iss, format );
parse(input, iss, out );
} // end parse()

void parse(const std::string& input, std::istringstream& iss, boost::posix_time::ptime& out ) { // (2)
// assumes iss has already been imbued with the desired time_input_facet
iss.str(input);
parse(iss, out );
} // end parse()

void parse(std::istringstream& iss, boost::posix_time::ptime& out ) { // (3)
// assumes iss has already been imbued with the desired time_input_facet AND has been initialized with the input str
iss >> out;
} // end parse()

} // end namespace mydt

Первой функцией, которую я написал, был parse (1). Это обеспечивает самый простой интерфейс; просто передайте входную строку, строку формата и переменную ptime OUT, и анализ будет завершен. Он использует статический поток istringstream для завершения синтаксического анализа, поэтому для этого не требуется никаких выделений. Но когда я посмотрел на функцию после того, как написал ее, я понял, что если у вас есть один формат, из которого вы постоянно хотите анализировать, то расточительно повторно выделять из него новый time_input_facet и наполнять его тем же потоком.

Так что я решил, что вы могли бы добиться большего, если бы вызывающий код создавал свой собственный (возможно, статический) istringstream, заполнял формат один раз, а затем неоднократно использовал этот istringstream для анализа. Поэтому я написал parse (2) для этой цели. Таким образом, вызывающий код может иметь одну выделенную функцию для каждого формата, например так:

void parseServerDT(const std::string& input, boost::posix_time::ptime& out );
void parseHostDT(const std::string& input, boost::posix_time::ptime& out );

// in main, or some other code context
boost::posix_time::ptime serverDT; parseServerDT(getServerDTStr(), serverDT );
boost::posix_time::ptime hostDT; parseHostDT(getHostDTStr(), hostDT );

void parseServerDT(const std::string& input, boost::posix_time::ptime& out ) {
static bool first = true;
static std::istringstream iss;
if (first) {
first = false;
mydt::imbueDTFormat(iss, SERVERDT_FORMAT );
} // end if
mydt::parse(input, iss, out );
} // end parseServerDT()

void parseHostDT(const std::string& input, boost::posix_time::ptime& out ) {
static bool first = true;
static std::istringstream iss;
if (first) {
first = false;
mydt::imbueDTFormat(iss, HOSTDT_FORMAT );
} // end if
mydt::parse(input, iss, out );
} // end parseHostDT()

Я думаю, что этот дизайн должен обеспечить максимальное удобство для вызова кода и минимизировать влияние на память и производительность. Вы можете определить столько функций parseXDT (), сколько захотите (и даже создать макрос, чтобы уменьшить дублирующийся код в этих функциях.)

Любая обратная связь будет высоко ценится. Спасибо!

3

Решение

По крайней мере

  1. сделать статику потоковой локальной. При отсутствии компиляторов это подразумевает их динамическое распределение (не проблема, так как это одноразовая стоимость)

  2. самое главное, очистить состояние ошибки потока и его содержимое перед повторным использованием

    void parseHostDT(const std::string& input, boost::posix_time::ptime& out ) {
    thread_local std::istringstream* iss = [] {
    first = false;
    mydt::imbueDTFormat(iss, HOSTDT_FORMAT);
    }();
    
    iss->clear();
    iss->str("");
    mydt::parse(input, iss, out);
    }
    
1

Другие решения


По вопросам рекламы [email protected]