mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-25 22:50:25 -05:00
Add thread-safe RiaStringPool utility and unit tests
Introduce RiaStringPool for efficient shared string storage and retrieval by index, with thread-safe access using shared mutex. Pre-allocate empty string at index 0. Add comprehensive unit tests covering core functionality, concurrency, edge cases, and realistic usage.
This commit is contained in:
1 parent
2573c17aed
commit
cff1ab08c4
5 files changed
+496
No files matched your search
@@ -23,6 +23,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RiaEclipseFileNameTools.h
|
${CMAKE_CURRENT_LIST_DIR}/RiaEclipseFileNameTools.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaFeatureCommandContext.h
|
${CMAKE_CURRENT_LIST_DIR}/RiaFeatureCommandContext.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaStringListSerializer.h
|
${CMAKE_CURRENT_LIST_DIR}/RiaStringListSerializer.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RiaStringPool.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaNncDefines.h
|
${CMAKE_CURRENT_LIST_DIR}/RiaNncDefines.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaPlotDefines.h
|
${CMAKE_CURRENT_LIST_DIR}/RiaPlotDefines.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaStimPlanModelDefines.h
|
${CMAKE_CURRENT_LIST_DIR}/RiaStimPlanModelDefines.h
|
||||||
@@ -67,6 +68,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RiaEclipseFileNameTools.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaEclipseFileNameTools.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaFeatureCommandContext.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaFeatureCommandContext.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaStringListSerializer.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaStringListSerializer.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RiaStringPool.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaNncDefines.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaNncDefines.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaPlotDefines.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaPlotDefines.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaStimPlanModelDefines.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaStimPlanModelDefines.cpp
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2026 Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight 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 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "RiaStringPool.h"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RiaStringPool& RiaStringPool::instance()
|
||||||
|
{
|
||||||
|
static RiaStringPool pool;
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RiaStringPool::RiaStringPool()
|
||||||
|
{
|
||||||
|
// Pre-allocate empty string at index 0
|
||||||
|
m_strings.push_back( "" );
|
||||||
|
m_stringToIndex[""] = 0;
|
||||||
|
m_emptyIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RiaStringPool::IndexType RiaStringPool::getIndex( const std::string& str )
|
||||||
|
{
|
||||||
|
// First try with shared lock for reading
|
||||||
|
{
|
||||||
|
std::shared_lock<std::shared_mutex> lock( m_mutex );
|
||||||
|
auto it = m_stringToIndex.find( str );
|
||||||
|
if ( it != m_stringToIndex.end() )
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to insert, acquire exclusive lock
|
||||||
|
std::unique_lock<std::shared_mutex> lock( m_mutex );
|
||||||
|
|
||||||
|
// Double-check after acquiring exclusive lock (another thread might have inserted it)
|
||||||
|
auto it = m_stringToIndex.find( str );
|
||||||
|
if ( it != m_stringToIndex.end() )
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexType newIndex = static_cast<IndexType>( m_strings.size() );
|
||||||
|
m_strings.push_back( str );
|
||||||
|
m_stringToIndex[m_strings.back()] = newIndex;
|
||||||
|
return newIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
const std::string& RiaStringPool::getString( IndexType index ) const
|
||||||
|
{
|
||||||
|
std::shared_lock<std::shared_mutex> lock( m_mutex );
|
||||||
|
|
||||||
|
if ( index >= m_strings.size() )
|
||||||
|
{
|
||||||
|
throw std::out_of_range( "String pool index out of range" );
|
||||||
|
}
|
||||||
|
return m_strings[index];
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2026 Equinor ASA
|
||||||
|
//
|
||||||
|
// ResInsight 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 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
/// String pool for memory-efficient storage of shared strings
|
||||||
|
/// Stores strings once and returns indices for lookups
|
||||||
|
//==================================================================================================
|
||||||
|
class RiaStringPool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using IndexType = uint32_t;
|
||||||
|
static constexpr IndexType INVALID_INDEX = static_cast<IndexType>( -1 );
|
||||||
|
|
||||||
|
static RiaStringPool& instance();
|
||||||
|
|
||||||
|
// Get or create an index for a string
|
||||||
|
IndexType getIndex( const std::string& str );
|
||||||
|
|
||||||
|
// Get string by index
|
||||||
|
const std::string& getString( IndexType index ) const;
|
||||||
|
|
||||||
|
// Get empty string index
|
||||||
|
IndexType getEmptyIndex() const { return m_emptyIndex; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
RiaStringPool();
|
||||||
|
RiaStringPool( const RiaStringPool& ) = delete;
|
||||||
|
RiaStringPool& operator=( const RiaStringPool& ) = delete;
|
||||||
|
|
||||||
|
mutable std::shared_mutex m_mutex;
|
||||||
|
std::vector<std::string> m_strings;
|
||||||
|
std::unordered_map<std::string, IndexType> m_stringToIndex;
|
||||||
|
IndexType m_emptyIndex;
|
||||||
|
};
|
||||||
@@ -69,6 +69,7 @@ set(SOURCE_UNITTEST_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RifCsvDataTableFormatter-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RifCsvDataTableFormatter-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaSummaryAddressAnalyzer-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaSummaryAddressAnalyzer-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaStdStringTools-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaStdStringTools-Test.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RiaStringPool-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaInterpolationTools-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaInterpolationTools-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RifWellMeasurementReader-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RifWellMeasurementReader-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaDateStringParser-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaDateStringParser-Test.cpp
|
||||||
|
|||||||
@@ -0,0 +1,349 @@
|
|||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#include "RiaStringPool.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <set>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RiaStringPoolTest, EmptyStringPreAllocated )
|
||||||
|
{
|
||||||
|
auto& pool = RiaStringPool::instance();
|
||||||
|
|
||||||
|
auto emptyIndex = pool.getIndex( "" );
|
||||||
|
EXPECT_EQ( pool.getEmptyIndex(), emptyIndex );
|
||||||
|
EXPECT_EQ( "", pool.getString( emptyIndex ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RiaStringPoolTest, BasicStringStorage )
|
||||||
|
{
|
||||||
|
auto& pool = RiaStringPool::instance();
|
||||||
|
|
||||||
|
std::string testStr = "FOPT";
|
||||||
|
auto index = pool.getIndex( testStr );
|
||||||
|
|
||||||
|
EXPECT_EQ( testStr, pool.getString( index ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RiaStringPoolTest, DuplicateStringsReturnSameIndex )
|
||||||
|
{
|
||||||
|
auto& pool = RiaStringPool::instance();
|
||||||
|
|
||||||
|
std::string testStr = "WOPT:WELL1";
|
||||||
|
auto index1 = pool.getIndex( testStr );
|
||||||
|
auto index2 = pool.getIndex( testStr );
|
||||||
|
auto index3 = pool.getIndex( testStr );
|
||||||
|
|
||||||
|
EXPECT_EQ( index1, index2 );
|
||||||
|
EXPECT_EQ( index2, index3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RiaStringPoolTest, MultipleUniqueStrings )
|
||||||
|
{
|
||||||
|
auto& pool = RiaStringPool::instance();
|
||||||
|
|
||||||
|
std::vector<std::string> testStrings = { "FOPT", "WOPT:WELL1", "GOPT:GROUP1", "BPR:10,20,30", "ROPR" };
|
||||||
|
|
||||||
|
std::vector<RiaStringPool::IndexType> indices;
|
||||||
|
for ( const auto& str : testStrings )
|
||||||
|
{
|
||||||
|
indices.push_back( pool.getIndex( str ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// All indices should be unique
|
||||||
|
std::set<RiaStringPool::IndexType> uniqueIndices( indices.begin(), indices.end() );
|
||||||
|
EXPECT_EQ( testStrings.size(), uniqueIndices.size() );
|
||||||
|
|
||||||
|
// Verify retrieval
|
||||||
|
for ( size_t i = 0; i < testStrings.size(); ++i )
|
||||||
|
{
|
||||||
|
EXPECT_EQ( testStrings[i], pool.getString( indices[i] ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RiaStringPoolTest, OutOfRangeThrows )
|
||||||
|
{
|
||||||
|
auto& pool = RiaStringPool::instance();
|
||||||
|
|
||||||
|
// Attempt to access index far beyond current size
|
||||||
|
EXPECT_THROW( pool.getString( 9999999 ), std::out_of_range );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RiaStringPoolTest, ThreadSafety )
|
||||||
|
{
|
||||||
|
auto& pool = RiaStringPool::instance();
|
||||||
|
|
||||||
|
const int numThreads = 10;
|
||||||
|
const int stringsPerThread = 100;
|
||||||
|
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
std::vector<std::vector<RiaStringPool::IndexType>> threadResults( numThreads );
|
||||||
|
|
||||||
|
// Create threads that all add the same strings
|
||||||
|
for ( int t = 0; t < numThreads; ++t )
|
||||||
|
{
|
||||||
|
threads.emplace_back(
|
||||||
|
[&pool, &threadResults, t, stringsPerThread]()
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < stringsPerThread; ++i )
|
||||||
|
{
|
||||||
|
std::string str = "STRING_" + std::to_string( i );
|
||||||
|
auto index = pool.getIndex( str );
|
||||||
|
threadResults[t].push_back( index );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for all threads to complete
|
||||||
|
for ( auto& thread : threads )
|
||||||
|
{
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all threads got the same indices for the same strings
|
||||||
|
for ( int i = 1; i < numThreads; ++i )
|
||||||
|
{
|
||||||
|
EXPECT_EQ( threadResults[0].size(), threadResults[i].size() );
|
||||||
|
for ( size_t j = 0; j < threadResults[0].size(); ++j )
|
||||||
|
{
|
||||||
|
EXPECT_EQ( threadResults[0][j], threadResults[i][j] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify string retrieval
|
||||||
|
for ( int i = 0; i < stringsPerThread; ++i )
|
||||||
|
{
|
||||||
|
std::string expectedStr = "STRING_" + std::to_string( i );
|
||||||
|
auto index = threadResults[0][i];
|
||||||
|
EXPECT_EQ( expectedStr, pool.getString( index ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RiaStringPoolTest, LargeNumberOfStrings )
|
||||||
|
{
|
||||||
|
auto& pool = RiaStringPool::instance();
|
||||||
|
|
||||||
|
const int numStrings = 10000;
|
||||||
|
std::vector<RiaStringPool::IndexType> indices;
|
||||||
|
|
||||||
|
// Add many unique strings
|
||||||
|
for ( int i = 0; i < numStrings; ++i )
|
||||||
|
{
|
||||||
|
std::string str = "VECTOR_" + std::to_string( i ) + "_DATA";
|
||||||
|
indices.push_back( pool.getIndex( str ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all can be retrieved
|
||||||
|
for ( int i = 0; i < numStrings; ++i )
|
||||||
|
{
|
||||||
|
std::string expectedStr = "VECTOR_" + std::to_string( i ) + "_DATA";
|
||||||
|
EXPECT_EQ( expectedStr, pool.getString( indices[i] ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RiaStringPoolTest, SpecialCharacters )
|
||||||
|
{
|
||||||
|
auto& pool = RiaStringPool::instance();
|
||||||
|
|
||||||
|
std::vector<std::string> specialStrings = { "String with spaces",
|
||||||
|
"String:with:colons",
|
||||||
|
"String/with/slashes",
|
||||||
|
"String,with,commas",
|
||||||
|
"String-with-dashes",
|
||||||
|
"String_with_underscores",
|
||||||
|
"String.with.dots",
|
||||||
|
"String|with|pipes",
|
||||||
|
"String@with@at",
|
||||||
|
"String#with#hash" };
|
||||||
|
|
||||||
|
for ( const auto& str : specialStrings )
|
||||||
|
{
|
||||||
|
auto index = pool.getIndex( str );
|
||||||
|
EXPECT_EQ( str, pool.getString( index ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RiaStringPoolTest, VeryLongStrings )
|
||||||
|
{
|
||||||
|
auto& pool = RiaStringPool::instance();
|
||||||
|
|
||||||
|
// Create a very long string
|
||||||
|
std::string longStr( 10000, 'A' );
|
||||||
|
longStr += "_UNIQUE";
|
||||||
|
|
||||||
|
auto index = pool.getIndex( longStr );
|
||||||
|
EXPECT_EQ( longStr, pool.getString( index ) );
|
||||||
|
|
||||||
|
// Verify same index on duplicate
|
||||||
|
auto index2 = pool.getIndex( longStr );
|
||||||
|
EXPECT_EQ( index, index2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RiaStringPoolTest, ConcurrentInsertAndRead )
|
||||||
|
{
|
||||||
|
auto& pool = RiaStringPool::instance();
|
||||||
|
|
||||||
|
const int numWriteThreads = 5;
|
||||||
|
const int numReadThreads = 5;
|
||||||
|
const int stringsPerWrite = 50;
|
||||||
|
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
|
||||||
|
// Create strings in multiple write threads
|
||||||
|
for ( int t = 0; t < numWriteThreads; ++t )
|
||||||
|
{
|
||||||
|
threads.emplace_back(
|
||||||
|
[&pool, t, stringsPerWrite]()
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < stringsPerWrite; ++i )
|
||||||
|
{
|
||||||
|
std::string str = "WRITE_" + std::to_string( t ) + "_" + std::to_string( i );
|
||||||
|
pool.getIndex( str );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read strings concurrently
|
||||||
|
for ( int t = 0; t < numReadThreads; ++t )
|
||||||
|
{
|
||||||
|
threads.emplace_back(
|
||||||
|
[&pool, t, stringsPerWrite]()
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < stringsPerWrite; ++i )
|
||||||
|
{
|
||||||
|
// Try to read strings that might be being created
|
||||||
|
std::string str = "WRITE_0_" + std::to_string( i );
|
||||||
|
auto index = pool.getIndex( str );
|
||||||
|
// Should not crash even if racing with writes
|
||||||
|
EXPECT_EQ( str, pool.getString( index ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto& thread : threads )
|
||||||
|
{
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all written strings are accessible
|
||||||
|
for ( int t = 0; t < numWriteThreads; ++t )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < stringsPerWrite; ++i )
|
||||||
|
{
|
||||||
|
std::string str = "WRITE_" + std::to_string( t ) + "_" + std::to_string( i );
|
||||||
|
auto index = pool.getIndex( str );
|
||||||
|
EXPECT_EQ( str, pool.getString( index ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RiaStringPoolTest, InvalidIndex )
|
||||||
|
{
|
||||||
|
auto& pool = RiaStringPool::instance();
|
||||||
|
|
||||||
|
// Test with INVALID_INDEX constant
|
||||||
|
EXPECT_THROW( pool.getString( RiaStringPool::INVALID_INDEX ), std::out_of_range );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RiaStringPoolTest, SimilarStrings )
|
||||||
|
{
|
||||||
|
auto& pool = RiaStringPool::instance();
|
||||||
|
|
||||||
|
// Test strings that are similar but not identical
|
||||||
|
std::vector<std::string> similarStrings = { "WOPT:WELL-1",
|
||||||
|
"WOPT:WELL-2",
|
||||||
|
"WOPT:WELL-10",
|
||||||
|
"WOPT:WELL-1A",
|
||||||
|
"WOPT:WELL_1",
|
||||||
|
"WOPT: WELL-1" };
|
||||||
|
|
||||||
|
std::vector<RiaStringPool::IndexType> indices;
|
||||||
|
for ( const auto& str : similarStrings )
|
||||||
|
{
|
||||||
|
indices.push_back( pool.getIndex( str ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// All should have different indices
|
||||||
|
std::set<RiaStringPool::IndexType> uniqueIndices( indices.begin(), indices.end() );
|
||||||
|
EXPECT_EQ( similarStrings.size(), uniqueIndices.size() );
|
||||||
|
|
||||||
|
// Verify each string retrieval
|
||||||
|
for ( size_t i = 0; i < similarStrings.size(); ++i )
|
||||||
|
{
|
||||||
|
EXPECT_EQ( similarStrings[i], pool.getString( indices[i] ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RiaStringPoolTest, CommonSummaryVectorNames )
|
||||||
|
{
|
||||||
|
auto& pool = RiaStringPool::instance();
|
||||||
|
|
||||||
|
// Test with realistic summary vector names
|
||||||
|
std::vector<std::string> vectorNames = { "FOPT",
|
||||||
|
"FWPT",
|
||||||
|
"FGPT",
|
||||||
|
"FOPR",
|
||||||
|
"FWPR",
|
||||||
|
"FGPR",
|
||||||
|
"WOPT:PROD-1",
|
||||||
|
"WWPT:PROD-1",
|
||||||
|
"WBHP:PROD-1",
|
||||||
|
"WOPT:INJ-1",
|
||||||
|
"GOPT:FIELD",
|
||||||
|
"BPR:10,15,20" };
|
||||||
|
|
||||||
|
// Store indices
|
||||||
|
std::vector<RiaStringPool::IndexType> indices;
|
||||||
|
for ( const auto& name : vectorNames )
|
||||||
|
{
|
||||||
|
indices.push_back( pool.getIndex( name ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request same strings again - should get same indices
|
||||||
|
for ( size_t i = 0; i < vectorNames.size(); ++i )
|
||||||
|
{
|
||||||
|
auto index = pool.getIndex( vectorNames[i] );
|
||||||
|
EXPECT_EQ( indices[i], index );
|
||||||
|
EXPECT_EQ( vectorNames[i], pool.getString( index ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user