Browse Source

Bunch of minor changes

alexey 2 years ago
parent
commit
d883373a2f

+ 1 - 1
CMakeLists.txt

@@ -181,7 +181,7 @@ endif (COVERAGE_TEST)
 
 # options for clang in C++
 target_compile_options ( lextra INTERFACE $<${CLANGCXX}:
-		-Wno-deprecated-register -Wno-missing-exception-spec -Wno-implicit-exception-spec-mismatch -Wno-invalid-offsetof> )
+		-Wno-deprecated-register -Wno-missing-exception-spec -Wno-implicit-exception-spec-mismatch -Wno-invalid-offsetof -Wc++11-narrowing> )
 
 # Checking for unaligned RAM access
 if (CMAKE_CROSSCOMPILING)

+ 1 - 1
src/libutils.h

@@ -36,7 +36,7 @@
 class ScopedHandle_c
 {
 public:
-	ScopedHandle_c ( void * pHandle )
+	explicit ScopedHandle_c ( void * pHandle )
 		: m_pHandle ( pHandle )
 	{}
 

+ 1 - 8
src/searchd.cpp

@@ -7165,7 +7165,7 @@ void SearchHandler_c::RunSubset ( int iStart, int iEnd )
 	// connect to remote agents and query them, if required
 	std::unique_ptr<SearchRequestBuilder_c> tReqBuilder;
 	CSphRefcountedPtr<RemoteAgentsObserver_i> tReporter { nullptr };
-	std::unique_ptr<ReplyParser_i> tParser;;
+	std::unique_ptr<ReplyParser_i> tParser;
 	if ( !dRemotes.IsEmpty() )
 	{
 		SwitchProfile(m_pProfile, SPH_QSTATE_DIST_CONNECT);
@@ -13760,13 +13760,6 @@ void sphHandleMysqlDelete ( StmtErrorReporter_i & tOut, const SqlStmt_t & tStmt,
 	tOut.Ok ( iAffected );
 }
 
-struct SessionVars_t
-{
-	bool			m_bAutoCommit = true;
-	bool			m_bInTransaction = false;
-	CSphVector<int64_t> m_dLastIds;
-};
-
 // fwd
 void HandleMysqlShowProfile ( RowBuffer_i & tOut, const QueryProfile_c & p, bool bMoreResultsFollow );
 

+ 29 - 17
src/searchdaemon.cpp

@@ -103,7 +103,7 @@ CheckLike::CheckLike( const char* sPattern )
 	*d = '\0';
 }
 
-bool CheckLike::Match( const char* sValue )
+bool CheckLike::Match ( const char* sValue ) const noexcept
 {
 	return sValue && ( m_sPattern.IsEmpty() || sphWildcardMatch( sValue, m_sPattern.cstr()));
 }
@@ -178,6 +178,19 @@ bool VectorLike::MatchAddf ( const char* sTemplate, ... )
 	return MatchAdd( sValue.cstr());
 }
 
+bool VectorLike::Matchf ( const char* sTemplate, ... ) const noexcept
+{
+	assert ( m_dHeadNames.GetLength() >= 1 );
+	va_list ap;
+	CSphString sValue;
+
+	va_start ( ap, sTemplate );
+	sValue.SetSprintfVa ( sTemplate, ap );
+	va_end ( ap );
+
+	return Match ( sValue.cstr() );
+}
+
 void VectorLike::Addf ( const char * sValueTmpl, ... )
 {
 	va_list ap;
@@ -247,18 +260,17 @@ void VectorLike::FillTail ( int iHas )
 }
 
 
-static const char * g_dIndexTypeName[1 + ( int ) IndexType_e::ERROR_] = {
-	"plain",
-	"template",
-	"rt",
-	"percolate",
-	"distributed",
-	"invalid"
-};
-
-CSphString GetTypeName( IndexType_e eType )
+const char* GetIndexTypeName ( IndexType_e eType )
 {
-	return g_dIndexTypeName[( int ) eType];
+	switch ( eType )
+	{
+	case IndexType_e::PLAIN : return "plain";
+	case IndexType_e::TEMPLATE: return "template";
+	case IndexType_e::RT: return "rt";
+	case IndexType_e::PERCOLATE: return "percolate";
+	case IndexType_e::DISTR: return "distributed";
+	default: return "invalid";
+	}
 }
 
 IndexType_e TypeOfIndexConfig( const CSphString& sType )
@@ -692,23 +704,23 @@ DWORD sphGetAddress ( const char * sHost, bool bFatal, bool bIP, CSphString * pF
 	if ( pResult->ai_next )
 	{
 		const bool bLocalHost = IsLocalhost ( uAddr );
-		char sAddrBuf[SPH_ADDRESS_SIZE+1];
+		std::array<char, SPH_ADDRESS_SIZE + 1> sAddrBuf{};
 		StringBuilder_c sBuf( "; ip=", "ip=" );
 
 		while ( pResult )
 		{
 			auto * pAddr = ( struct sockaddr_in *)pResult->ai_addr;
 			DWORD uNextAddr = pAddr->sin_addr.s_addr;
-			sphFormatIP( sAddrBuf, sizeof( sAddrBuf ), uNextAddr );
-			sBuf += sAddrBuf; // can not use << as builder appends string buffer with tail '\0' and next chunks are invisible
+			sphFormatIP( sAddrBuf.data(), sAddrBuf.size(), uNextAddr );
+			sBuf += sAddrBuf.data(); // can not use << as builder appends string buffer with tail '\0' and next chunks are invisible
 			pResult = pResult->ai_next;
 
 			if ( bLocalHost && !IsLocalhost ( uNextAddr ) )
 				uAddr = uNextAddr;
 		}
 
-		sphFormatIP( sAddrBuf, sizeof( sAddrBuf ), uAddr );
-		sphWarning( "multiple addresses (%s) found for '%s', using first one (%s)", sBuf.cstr(), sHost, sAddrBuf );
+		sphFormatIP( sAddrBuf.data(), sAddrBuf.size(), uAddr );
+		sphWarning( "multiple addresses (%s) found for '%s', using first one (%s)", sBuf.cstr(), sHost, sAddrBuf.data() );
 	}
 
 	return uAddr;

+ 14 - 24
src/searchdaemon.h

@@ -100,11 +100,11 @@
 #include "coroutine.h"
 #include "conversion.h"
 
-#define SPHINXAPI_PORT            9312
-#define SPHINXQL_PORT            9306
-#define SPH_ADDRESS_SIZE        sizeof("000.000.000.000")
-#define SPH_ADDRPORT_SIZE        sizeof("000.000.000.000:00000")
-#define NETOUTBUF                8192
+constexpr int SPHINXAPI_PORT	= 9312;
+constexpr int SPHINXQL_PORT		= 9306;
+constexpr int SPH_ADDRESS_SIZE	= sizeof("000.000.000.000");
+constexpr int SPH_ADDRPORT_SIZE	= sizeof("000.000.000.000:00000");
+constexpr int NETOUTBUF			= 8192;
 
 volatile bool& sphGetGotSighup() noexcept;
 volatile bool& sphGetGotSigusr1() noexcept;
@@ -223,7 +223,7 @@ private:
 
 public:
 	explicit CheckLike( const char* sPattern );
-	bool Match( const char* sValue );
+	bool Match( const char* sValue ) const noexcept;
 };
 
 using Generator_fn = std::function<CSphString ( void )>;
@@ -249,6 +249,7 @@ public:
 	// returns true, if single value matches
 	bool MatchAdd( const char* sValue );
 	bool MatchAddf ( const char* sTemplate, ... ) __attribute__ (( format ( printf, 2, 3 )));
+	bool Matchf ( const char* sTemplate, ... ) const noexcept __attribute__ ( ( format ( printf, 2, 3 ) ) );
 
 	// unconditionally add formatted
 	void Addf ( const char * sValueTmpl, ... );
@@ -260,7 +261,7 @@ public:
 	void MatchTupletFn ( const char * sKey, GeneratorS_fn && fnValuePrinter );
 };
 
-CSphString GetTypeName ( IndexType_e eType );
+const char* GetIndexTypeName ( IndexType_e eType );
 IndexType_e TypeOfIndexConfig ( const CSphString & sType );
 
 // forwards from searchd
@@ -726,43 +727,32 @@ struct ServedDesc_t : public ISphRefcountedMT
 	// mutable is one which can be insert/replace
 	static bool IsMutable ( const ServedDesc_t* pServed )
 	{
-		if ( !pServed )
-			return false;
-		return pServed->m_eType==IndexType_e::RT || pServed->m_eType==IndexType_e::PERCOLATE;
+		return pServed && ( pServed->m_eType == IndexType_e::RT || pServed->m_eType == IndexType_e::PERCOLATE );
 	}
 
 	// local is one stored locally on disk
 	static bool IsLocal ( const ServedDesc_t* pServed )
 	{
-		if ( !pServed )
-			return false;
-		return IsMutable ( pServed ) || pServed->m_eType==IndexType_e::PLAIN;
+		return pServed && ( IsMutable ( pServed ) || pServed->m_eType == IndexType_e::PLAIN );
 	}
 
 	// cluster is one which can deals with replication
 	static bool IsCluster ( const ServedDesc_t* pServed )
 	{
-		if ( !pServed )
-			return false;
-		return !pServed->m_sCluster.IsEmpty ();
+		return pServed && !pServed->m_sCluster.IsEmpty();
 	}
 
 	// CanSelect is one which supports select ... from (at least full-scan).
 	static bool IsSelectable ( const ServedDesc_t* pServed )
 	{
-		if ( !pServed )
-			return false;
-		return IsFT ( pServed ) || pServed->m_eType==IndexType_e::PERCOLATE;
+		return pServed  && ( IsFT ( pServed ) || pServed->m_eType == IndexType_e::PERCOLATE );
 	}
 
 	// FT is one which supports full-text searching
 	static bool IsFT ( const ServedDesc_t* pServed )
 	{
-		if ( !pServed )
-			return false;
-		return pServed->m_eType==IndexType_e::PLAIN
-			|| pServed->m_eType==IndexType_e::RT
-			|| pServed->m_eType==IndexType_e::DISTR; // fixme! distrs not necessary ft.
+		return pServed && ( pServed->m_eType == IndexType_e::PLAIN || pServed->m_eType == IndexType_e::RT || pServed->m_eType == IndexType_e::DISTR );
+		// fixme! distrs not necessary ft.
 	}
 };
 

+ 2 - 2
src/searchdconfig.cpp

@@ -435,7 +435,7 @@ bool IndexDesc_t::Parse ( const JsonObj_c & tJson, CSphString & sWarning, CSphSt
 void IndexDesc_t::Save ( JsonObj_c & tIndexes ) const
 {
 	JsonObj_c tIdx;
-	tIdx.AddStr ( "type", GetTypeName ( m_eType ) );
+	tIdx.AddStr ( "type", GetIndexTypeName ( m_eType ) );
 
 	if ( m_eType==IndexType_e::DISTR )
 		m_tDistr.Save(tIdx);
@@ -451,7 +451,7 @@ void IndexDesc_t::Save ( JsonObj_c & tIndexes ) const
 
 void IndexDesc_t::Save ( CSphConfigSection & hIndex ) const
 {
-	hIndex.Add ( CSphVariant ( GetTypeName ( m_eType ).cstr() ), "type" );
+	hIndex.Add ( CSphVariant ( GetIndexTypeName ( m_eType ) ), "type" );
 
 	if ( m_eType==IndexType_e::DISTR )
 		m_tDistr.Save (hIndex);

+ 1 - 3
src/searchdha.cpp

@@ -82,9 +82,7 @@ HostDashboard_t::HostDashboard_t ( const HostDesc_t & tHost )
 {
 	assert ( !tHost.m_pDash );
 	m_tHost.CloneFromHost ( tHost );
-	m_iLastQueryTime = m_iLastAnswerTime = sphMicroTimer ();
-	for ( auto & dMetric : m_dPeriodicMetrics )
-		dMetric.m_dMetrics.Reset ();
+	for_each ( m_dPeriodicMetrics, [] ( auto& dMetric ) { dMetric.m_dMetrics.Reset(); } );
 }
 
 HostDashboard_t::~HostDashboard_t ()

+ 2 - 2
src/searchdha.h

@@ -231,8 +231,8 @@ struct HostDashboard_t : public ISphRefcountedMT
 	PersistentConnectionsPool_c * m_pPersPool = nullptr;    // persistence pool also lives here, one per dashboard
 
 	mutable RwLock_t m_dMetricsLock;        // guards everything essential (see thread annotations)
-	int64_t m_iLastAnswerTime GUARDED_BY ( m_dMetricsLock );    // updated when we get an answer from the host
-	int64_t m_iLastQueryTime GUARDED_BY ( m_dMetricsLock ) = 0;    // updated when we send a query to a host
+	int64_t m_iLastAnswerTime GUARDED_BY ( m_dMetricsLock ) = sphMicroTimer();    // updated when we get an answer from the host
+	int64_t m_iLastQueryTime GUARDED_BY ( m_dMetricsLock ) = sphMicroTimer();    // updated when we send a query to a host
 	int64_t m_iErrorsARow GUARDED_BY ( m_dMetricsLock ) = 0;        // num of errors a row, updated when we update the general statistic.
 	DWORD m_uPingTripUS = 0;		// round-trip in uS. We send ping with current time, on receive answer compare with current time and fix that difference
 

+ 5 - 5
src/searchdhttp.cpp

@@ -1031,7 +1031,7 @@ bool HttpHandler_c::CheckValid ( const ServedIndex_c* pServed, const CSphString&
 	}
 	if ( pServed->m_eType!=eType )
 	{
-		FormatError ( SPH_HTTP_STATUS_500, "table '%s' is not %s", sIndex.cstr(), GetTypeName ( eType ).cstr() );
+		FormatError ( SPH_HTTP_STATUS_500, "table '%s' is not %s", sIndex.cstr(), GetIndexTypeName ( eType ) );
 		return false;
 	}
 	return true;
@@ -1290,7 +1290,7 @@ protected:
 
 typedef std::pair<CSphString,MysqlColumnType_e> ColumnNameType_t;
 
-static const char * GetTypeName ( MysqlColumnType_e eType )
+static const char * GetMysqlTypeName ( MysqlColumnType_e eType )
 {
 	switch ( eType )
 	{
@@ -1304,7 +1304,7 @@ static const char * GetTypeName ( MysqlColumnType_e eType )
 	};
 }
 
-static MysqlColumnType_e GetTypeName ( const CSphString& sType )
+static MysqlColumnType_e GetMysqlTypeByName ( const CSphString& sType )
 {
 	if ( sType=="decimal")
 		return MYSQL_COL_DECIMAL;
@@ -1330,7 +1330,7 @@ static MysqlColumnType_e GetTypeName ( const CSphString& sType )
 
 JsonEscapedBuilder& operator<< ( JsonEscapedBuilder& tOut, MysqlColumnType_e eType )
 {
-	tOut.FixupSpacedAndAppendEscaped ( GetTypeName ( eType ) );
+	tOut.FixupSpacedAndAppendEscaped ( GetMysqlTypeName ( eType ) );
 	return tOut;
 }
 
@@ -1544,7 +1544,7 @@ void ConvertJsonDataset ( const bson::Bson_c & tBson, const char * sStmt, RowBuf
 		{
 			assert ( tColumnNode.IsAssoc() ); // like {"id":{"type":"long long"}}
 			tColumnNode.ForEach( [&] ( CSphString&& sName, const NodeHandle_t& tNode ) {
-				auto eType = GetTypeName ( String ( Bson_c ( tNode ).ChildByName ( "type" ) ) );
+				auto eType = GetMysqlTypeByName ( String ( Bson_c ( tNode ).ChildByName ( "type" ) ) );
 				dSqlColumns.Add ( {sName,eType});
 			} );
 		}

+ 1 - 1
src/searchdreplication.cpp

@@ -4643,7 +4643,7 @@ bool RemoteLoadIndex ( const PQRemoteData_t & tCmd, PQRemoteReply_t & tRes, CSph
 	if ( !pMerge )
 		return false;
 
-	CSphString sType = GetTypeName ( tCmd.m_eIndex );
+	CSphString sType = GetIndexTypeName ( tCmd.m_eIndex );
 	if ( tCmd.m_eIndex!=IndexType_e::PERCOLATE && tCmd.m_eIndex!=IndexType_e::RT )
 	{
 		sError.SetSprintf ( "unsupported type '%s' in table '%s'", sType.cstr(), tCmd.m_sIndex.cstr() );

+ 31 - 4
src/sphinxjson.h

@@ -234,7 +234,7 @@ public:
 	ScopedComma_c Named ( const char * sName )
 	{
 		Base_T::FixupSpacedAndAppendEscaped ( sName );
-		AppendRawChunk ( {":", 1} );
+		AppendRawChunk ( FROMS ( ":" ) );
 		SkipNextComma ();
 		return { *this, nullptr };
 	}
@@ -261,7 +261,7 @@ public:
 
 	int NamedBlock( const char* sName )
 	{
-		Base_T::FixupSpacedAndAppendEscaped( sName );
+		FixupSpacedAndAppendEscaped( sName );
 		AppendRawChunk( { ":", 1 } );
 		SkipNextComma();
 		return MuteBlock();
@@ -290,13 +290,13 @@ public:
 	void NamedString ( const char* szName, const char* szValue )
 	{
 		Named ( szName );
-		Base_T::FixupSpacedAndAppendEscaped ( szValue );
+		FixupSpacedAndAppendEscaped ( szValue );
 	}
 
 	void NamedString ( const char* szName, Str_t sValue )
 	{
 		Named ( szName );
-		Base_T::FixupSpacedAndAppendEscaped ( sValue.first, sValue.second );
+		FixupSpacedAndAppendEscaped ( sValue.first, sValue.second );
 	}
 
 	void NamedString ( const char* szName, const CSphString& sValue )
@@ -310,6 +310,12 @@ public:
 			NamedString ( szName, sValue );
 	}
 
+	void NamedStringNonDefault ( const char* szName, const CSphString& sValue, CSphString sDefault )
+	{
+		if ( sValue!=sDefault )
+			NamedString ( szName, sValue );
+	}
+
 	template<typename T>
 	void NamedVal ( const char* szName, T tValue )
 	{
@@ -324,6 +330,27 @@ public:
 			NamedVal ( szName, tValue );
 	}
 
+	void String ( const char* szValue )
+	{
+		FixupSpacedAndAppendEscaped ( szValue );
+	}
+
+	void String ( Str_t sValue )
+	{
+		FixupSpacedAndAppendEscaped ( sValue.first, sValue.second );
+	}
+
+	void String ( const CSphString& sValue )
+	{
+		FixupSpacedAndAppendEscaped ( sValue.cstr() );
+	}
+
+	void StringNonEmpty ( const CSphString& sValue )
+	{
+		if ( !sValue.IsEmpty() )
+			String ( sValue );
+	}
+
 	// non-escaped.
 	// Imply, that only internal strings no-need of escape (say, pre-escaped) in use,
 	// works faster, because skip escaping pass.

+ 2 - 2
src/sphinxutils.cpp

@@ -3185,11 +3185,11 @@ bool sphDetectChinese ( const BYTE * szBuffer, int iLength )
 
 #if HAVE_DLOPEN
 
-CSphDynamicLibrary::CSphDynamicLibrary ( const char * sPath )
+CSphDynamicLibrary::CSphDynamicLibrary ( const char * sPath, bool bGlobal )
 	: m_bReady ( false )
 	, m_pLibrary ( nullptr )
 {
-	m_pLibrary = dlopen ( sPath, RTLD_NOW | RTLD_GLOBAL );
+	m_pLibrary = dlopen ( sPath, RTLD_NOW | ( bGlobal ? RTLD_GLOBAL : RTLD_LOCAL ) );
 	if ( !m_pLibrary )
 		sphLogDebug ( "dlopen(%s) failed", sPath );
 	else

+ 7 - 6
src/sphinxutils.h

@@ -200,11 +200,12 @@ namespace sph
 	SmallStringHash_T<CSphVariant> ParseKeyValueVars ( const char * sBuf );
 
 	template<typename FnFilter>
-	void ParseKeyValues ( const char * sBuf, FnFilter && fnFilter )
+	void ParseKeyValues ( const char * sBuf, FnFilter fnFilter, const char* szDelim = ",; \t\n\r" )
 	{
-		if ( sBuf && ( *sBuf ))
-		{
-			sph::Split ( sBuf, -1, ",; \t\n\r", [&] (const char* sToken, int iLen)
+		if ( !sBuf || ( !*sBuf ))
+			return;
+
+		sph::Split ( sBuf, -1, szDelim, [&] (const char* sToken, int iLen)
 			{
 				auto dOption = sphSplit ( sToken, iLen, "=" );
 				assert ( dOption.GetLength ()==2 ); // as 'key' = 'value'
@@ -212,7 +213,6 @@ namespace sph
 				fnFilter ( std::move ( dOption[0] ), std::move ( dOption[1] ));
 			});
 		}
-	}
 
 	/// zero-copy split by the given boundaries, result valid until sIn lives.
 	void Split ( StrtVec_t& dOut, const char* sIn, const char* sBounds );
@@ -438,13 +438,14 @@ class CSphDynamicLibrary : public ISphNoncopyable
 	void *		m_pLibrary; // internal handle
 
 public:
-	explicit CSphDynamicLibrary ( const char* sPath );
+	explicit CSphDynamicLibrary ( const char* sPath, bool bGlobal=true );
 
 	// We are suppose, that library is loaded once when necessary, and will alive whole lifetime of utility.
 	// So, no need to explicitly desctruct it, this is intended leak.
 	~CSphDynamicLibrary ();
 
 	bool		LoadSymbols ( const char** sNames, void*** pppFuncs, int iNum );
+	inline void * GetLib() const noexcept { return m_pLibrary; }
 };
 
 /// collect warnings/errors from any suitable context.

+ 1 - 0
src/std/bitvec_impl.h

@@ -10,6 +10,7 @@
 // did not, you can find it at http://www.gnu.org
 //
 
+#include "bitcount.h"
 #include <utility>
 #include <cstring>
 

+ 5 - 5
src/std/iterations.h

@@ -13,19 +13,19 @@
 #pragma once
 
 template<typename CONTAINER, typename FILTER>
-inline bool all_of ( const CONTAINER& dData, FILTER&& cond );
+inline bool all_of ( const CONTAINER& dData, FILTER cond );
 
 template<typename CONTAINER, typename FILTER>
-inline bool any_of ( const CONTAINER& dData, FILTER&& cond );
+inline bool any_of ( const CONTAINER& dData, FILTER cond );
 
 template<typename CONTAINER, typename FILTER>
-inline bool none_of ( const CONTAINER& dData, FILTER&& cond );
+inline bool none_of ( const CONTAINER& dData, FILTER cond );
 
 template<typename CONTAINER, typename FILTER>
-inline int64_t count_of ( const CONTAINER& dData, FILTER&& cond );
+inline int64_t count_of ( const CONTAINER& dData, FILTER cond );
 
 template<typename CONTAINER, typename ACTION>
-void for_each ( CONTAINER& dData, ACTION&& fnAction );
+void for_each ( CONTAINER&& dData, ACTION fnAction );
 
 #define ARRAY_FOREACH( _index, _array ) \
 	for ( int _index = 0; _index < _array.GetLength(); ++_index )

+ 5 - 5
src/std/iterations_impl.h

@@ -13,7 +13,7 @@
 #include "thread_annotations.h"
 
 template<typename CONTAINER, typename FILTER>
-FORCE_INLINE bool all_of ( const CONTAINER& dData, FILTER&& cond ) NO_THREAD_SAFETY_ANALYSIS
+FORCE_INLINE bool all_of ( const CONTAINER& dData, FILTER cond ) NO_THREAD_SAFETY_ANALYSIS
 {
 	for ( const auto& dItem : dData )
 		if ( !cond ( dItem ) )
@@ -22,7 +22,7 @@ FORCE_INLINE bool all_of ( const CONTAINER& dData, FILTER&& cond ) NO_THREAD_SAF
 }
 
 template<typename CONTAINER, typename FILTER>
-FORCE_INLINE bool any_of ( const CONTAINER& dData, FILTER&& cond ) NO_THREAD_SAFETY_ANALYSIS
+FORCE_INLINE bool any_of ( const CONTAINER& dData, FILTER cond ) NO_THREAD_SAFETY_ANALYSIS
 {
 	for ( const auto& dItem : dData )
 		if ( cond ( dItem ) )
@@ -32,13 +32,13 @@ FORCE_INLINE bool any_of ( const CONTAINER& dData, FILTER&& cond ) NO_THREAD_SAF
 }
 
 template<typename CONTAINER, typename FILTER>
-FORCE_INLINE bool none_of ( const CONTAINER& dData, FILTER&& cond ) NO_THREAD_SAFETY_ANALYSIS
+FORCE_INLINE bool none_of ( const CONTAINER& dData, FILTER cond ) NO_THREAD_SAFETY_ANALYSIS
 {
 	return !any_of ( dData, std::forward<FILTER> ( cond ) );
 }
 
 template<typename CONTAINER, typename FILTER>
-FORCE_INLINE int64_t count_of ( const CONTAINER& dData, FILTER&& cond ) NO_THREAD_SAFETY_ANALYSIS
+FORCE_INLINE int64_t count_of ( const CONTAINER& dData, FILTER cond ) NO_THREAD_SAFETY_ANALYSIS
 {
 	int64_t iRes = 0;
 	for ( const auto& dItem : dData )
@@ -49,7 +49,7 @@ FORCE_INLINE int64_t count_of ( const CONTAINER& dData, FILTER&& cond ) NO_THREA
 }
 
 template<typename CONTAINER, typename ACTION>
-FORCE_INLINE void for_each ( CONTAINER& dData, ACTION&& fnAction ) NO_THREAD_SAFETY_ANALYSIS
+FORCE_INLINE void for_each ( CONTAINER&& dData, ACTION fnAction ) NO_THREAD_SAFETY_ANALYSIS
 {
 	for ( auto& dItem : dData )
 		fnAction ( dItem );

+ 5 - 1
src/std/string.h

@@ -184,9 +184,13 @@ CSphString SphSprintfVa ( const char* sTemplate, va_list ap );
 CSphString SphSprintf ( const char* sTemplate, ... );
 
 /// commonly used
+void ToLower ( Str_t sVal );
+
 using StrVec_t = CSphVector<CSphString>;
 using StrtVec_t = CSphVector<Str_t>;
 
-void ToLower ( Str_t sVal );
+#include "fixedvector.h"
+using FixedStrVec_t = CSphFixedVector<CSphString>;
+using FixedStrtVec_t = CSphFixedVector<Str_t>;
 
 #include "string_impl.h"

+ 4 - 8
src/std/stringbuilder.cpp

@@ -345,13 +345,9 @@ const Str_t& StringBuilder_c::LazyComma_c::RawComma ( const std::function<void (
 }
 
 
-CSphString ConcatWarnings ( StrVec_t & dWarnings )
+CSphString StrVec2Str ( const VecTraits_T<CSphString>& tVec, const char* szDelim ) noexcept
 {
-	dWarnings.Uniq();
-
-	StringBuilder_c sRes ( "; " );
-	for ( const auto & i : dWarnings )
-		sRes << i;
-
-	return sRes.cstr();
+	StringBuilder_c tOut ( szDelim );
+	tVec.Apply ( [&tOut] ( const CSphString& sNode ) { tOut << sNode; } );
+	return { tOut };
 }

+ 8 - 4
src/std/stringbuilder.h

@@ -128,7 +128,7 @@ public:
 
 	// arbitrary output all params according to their << implementations (inlined in compile time).
 	template<typename... Params>
-	StringBuilder_c &	Sprint ( const Params&... tParams );
+	StringBuilder_c& Sprint ( Params&&... tParams );
 
 	// comma manipulations
 	// start new comma block; return index of it (for future possible reference in FinishBlocks())
@@ -214,10 +214,10 @@ StringBuilder_c& operator<< ( StringBuilder_c& tOut, timespan_t tVal );
 StringBuilder_c& operator<< ( StringBuilder_c& tOut, timestamp_t tVal );
 
 template<typename INT, int iPrec>
-StringBuilder_c& operator<< ( StringBuilder_c& tOut, FixedFrac_T<INT, iPrec>&& tVal );
+StringBuilder_c& operator<< ( StringBuilder_c& tOut, FixedFrac_T<INT, iPrec> tVal );
 
 template<typename INT, int iBase, int iWidth, int iPrec, char cFill>
-StringBuilder_c& operator<< ( StringBuilder_c& tOut, FixedNum_T<INT, iBase, iWidth, iPrec, cFill>&& tVal );
+StringBuilder_c& operator<< ( StringBuilder_c& tOut, FixedNum_T<INT, iBase, iWidth, iPrec, cFill> tVal );
 
 // helpers
 inline void Grow ( StringBuilder_c& tBuilder, int iInc )
@@ -230,7 +230,11 @@ inline char* Tail ( StringBuilder_c& tBuilder )
 	return tBuilder.end();
 }
 
+CSphString StrVec2Str ( const VecTraits_T<CSphString>& tVec, const char* szDelim = "," ) noexcept;
 
-CSphString ConcatWarnings ( StrVec_t & dWarnings );
+inline CSphString ConcatWarnings ( const VecTraits_T<CSphString>& tVec ) noexcept
+{
+	return StrVec2Str ( tVec, "; " );
+}
 
 #include "stringbuilder_impl.h"

+ 4 - 4
src/std/stringbuilder_impl.h

@@ -302,9 +302,9 @@ inline void StringBuilder_c::LazyComma_c::Swap ( LazyComma_c & rhs ) noexcept
 }
 
 template<typename... Params>
-StringBuilder_c& StringBuilder_c::Sprint ( const Params&... tValues )
+StringBuilder_c& StringBuilder_c::Sprint ( Params&&... tValues )
 {
-	(void)std::initializer_list<int> { ( *this << tValues, 0 )... };
+	(void)std::initializer_list<int> { ( *this << std::forward<Params>(tValues), 0 )... };
 	return *this;
 }
 
@@ -329,14 +329,14 @@ inline StringBuilder_c& operator<< ( StringBuilder_c& tOut, timestamp_t tVal )
 }
 
 template<typename INT, int iPrec>
-inline StringBuilder_c& operator<< ( StringBuilder_c& tOut, FixedFrac_T<INT, iPrec>&& tVal )
+inline StringBuilder_c& operator<< ( StringBuilder_c& tOut, FixedFrac_T<INT, iPrec> tVal )
 {
 	tOut.template IFtoA<INT, iPrec>(tVal);
 	return tOut;
 }
 
 template<typename INT, int iBase, int iWidth, int iPrec, char cFill>
-StringBuilder_c& operator<< ( StringBuilder_c& tOut, FixedNum_T<INT, iBase, iWidth, iPrec, cFill>&& tVal )
+StringBuilder_c& operator<< ( StringBuilder_c& tOut, FixedNum_T<INT, iBase, iWidth, iPrec, cFill> tVal )
 {
 	tOut.template NtoA<INT, iBase, iWidth, iPrec, cFill> ( tVal.m_tVal );
 	return tOut;

+ 1 - 0
src/std/vectraits.h

@@ -13,6 +13,7 @@
 #pragma once
 
 #include "generics.h"
+#include "ints.h"
 
 /// vector traits - provides generic ops over a typed blob (vector).
 /// just provide common operators; doesn't manage buffer anyway

+ 0 - 1
src/threadutils.cpp

@@ -106,7 +106,6 @@ int GetOsProcessId()
 #include "event.h"
 
 #include <atomic>
-#include <optional>
 
 //////////////////////////////////////////////////////////////////////////
 /// functional threadpool with minimum footprint