'std::logic_error' what(): basic_string::_M_construct null not valid - c++

I have this cpp file and I have to write write a header for it, with an own template class. When I try to run the code it throws this 'std::logic_error' what(): basic_string::_M_construct null not valid error. It causes by the map_aligner<std::string, std::string> lsa; line but I don't really understand why and how to solve this issue.
The cpp:
#include <iostream>
#include "mapalign.h"
#include <string>
#include <algorithm>
#include <map>
#include "mapalign.h"
struct string_size_less
{
bool operator()( const std::string& a,
const std::string& b ) const
{
return a.size() < b.size();
}
};
const int max = 1000;
bool check()
{
std::map<std::string, int> sma;
std::map<std::string, int> smb;
std::map<std::string, int> smc;
map_aligner<std::string, int> sa;
sa.add( sma );
sa.add( smb );
sa.add( smc );
sma[ "C++" ] = 1;
smb[ "Ada" ] = 2;
smc[ "C" ] = 3;
smc[ "Python" ] = 4;
smc[ "Ada"] = 5;
sa.align();
std::map<int, double> ima;
std::map<int, double> imb;
for( int i = 0; i < max; ++i )
{
if ( 0 == i % 2 )
{
ima[ i ] = max - i;
}
else
{
imb[ i ] = max;
}
}
map_aligner<int, double> ia;
ia.add( ima );
ia.add( imb );
ia.align();
if ( ( 4 != sma.size() && 1 != imb.count( 0 )) || max * 1U != ima.size() ||
1 != smc.count( "C++" ) || "Ada" != sma.begin()->first ||
0 != sma.begin()->second || 4 != smc.size() ||
1 != smb.count( "Python" ) || 0 != imb.begin()->first ||
0.8 <= imb.begin()->second || 1 != imb.count( max / 2 ) )
{
return false;
}
sma[ "Pascal" ] = 5;
sa.set_filler( max );
sa.align();
std::map<std::string, std::string> langsa;
langsa[ "C++" ] = "<3";
langsa[ "Python" ] = ":|";
std::map<std::string, std::string> langsb;
langsb[ "Brainfuck" ] = ":S";
langsb[ "Python" ] = ":/";
langsb[ "C" ] = ":)";
map_aligner<std::string, std::string> lsa;
lsa.add( langsa );
lsa.add( langsb );
lsa.align();
lsa.erase( "Python" );
if ( 0 != langsa.count( "Python" ) || max != smc[ "Pascal" ] ||
!langsa.begin()->second.empty() || max != smb[ "Pascal" ] ||
2 * 1U != langsb.begin()->second.size() ||
0 != langsb.count( "Python" ) || 1 != langsb.count( "C++" ) )
{
return false;
}
std::map<std::string, std::string, string_size_less> lma;
std::map<std::string, std::string, string_size_less> lmb;
std::map<std::string, std::string, string_size_less> lmc;
lma[ "C++" ] = ":D";
lmb[ "Eiffel" ] = ":P";
lmc[ "C" ] = "8-)";
lmc[ "Ada" ] = "!";
map_aligner<std::string, std::string, string_size_less> ls;
ls.add( lma );
(ls += lmb) += lmc;
ls.align();
std::cout << (3 == ls.count()) << (1 == lmc.count( "Ada" )) <<
(3 * 1U == lmb.size()) << (1 == lma.count( "Python" )) <<
(2 == lsa.count()) << (2 == ia.count()) ;
return ( 3 == ls.count() && 1 == lmc.count( "Ada" ) &&
3 * 1U == lmb.size() && 1 == lma.count( "Python" ) &&
2 == lsa.count() && 2 == ia.count() );
}
int main()
{
std::cout
<< "Your solution is "
<< (check() ? "" : "not ")
<< "ready for submission."
<< std::endl;
}
The h:
#ifndef MAPALIGN_H
#define MAPALIGN_H
#include <vector>
#include <map>
#include <typeinfo>
template<typename KEY, typename VALUE, typename COMPARE = std::less<KEY>>
class map_aligner{
public:
typedef typename std::map<KEY, VALUE, COMPARE>::size_type size_type;
map_aligner() {}
void add(std::map<KEY, VALUE, COMPARE>& m) {
maps_.push_back(&m);
}
map_aligner<KEY, VALUE, COMPARE> operator+=(std::map<KEY, VALUE, COMPARE>& m){
return maps_.push_back(&m);
}
size_type count() const {
return maps_.size();
}
void align(){
for(int i = 0; i != (int)maps_.size(); i++ ){
std::map<KEY, VALUE>* first_map = maps_.at(i);
for(typename std::map<KEY, VALUE>::iterator j = first_map->begin(); j !=first_map->end(); j++ ){
for(int h = 0; h != (int)maps_.size(); h++ ){
std::map<KEY, VALUE>* second_map = maps_.at(h);
if(first_map != second_map && notContainsPair(second_map, j)){
second_map->insert(std::make_pair(j->first, filler_));
}
}
}
}
}
bool notContainsPair(std::map<KEY, VALUE>* map,typename std::map<KEY, VALUE>::iterator it){
for(typename std::map<KEY, VALUE>::iterator g = map->begin(); g != map->end(); g++ ){
if(it->first != g->first){
return true;
}
}
return false;
}
void set_filler(VALUE filler){
filler_ = filler;
}
void erase(KEY key){
for(int h = 0; h != (int)maps_.size(); h++ ){
std::map<KEY, VALUE>* map = maps_.at(h);
typename std::map<KEY, VALUE>::iterator it;
if(typeid(it->first) != typeid(it->first)){
map->erase(key);
}
}
}
private:
std::vector<std::map<KEY, VALUE, COMPARE>*> maps_;
VALUE filler_ = (VALUE) NULL;
};
#endif

That error is caused by you trying to construct a string with a null pointer.
Now look at the code that causes the error
map_aligner<std::string, std::string> lsa;
Both template parameters are strings.
Now look at this code in map_aligner
VALUE filler_ = (VALUE) NULL;
VALUE is a std::string so this code is constructing a string from a null pointer, exactly as the error indicates.
I don't know, but I guess you just want this
VALUE filler_ = VALUE();
It's a dangerous thing to try and construct an arbitrary type from NULL.

Related

Halstead Metrics : Display list of operators and operands from code using C++

I'm really new to C++, I've found this piece of code on GitHub, this code calculate the Halstead Metrics and it's works very well, I'm trying to make it display the operators and operands like this, each operator and operands display with its occurrences :
#include <iostream>
#include <fstream>
#include <regex>
#include <vector>
#include <map>
#include <set>
#include <climits>
#define ll long long
#define pb push_back
#define inf INT_MAX
#define ninf INT_MIN
#define MAXL 100001
#define fo(i,a,b) for(int i=a;i<b;i++)
#define foreach(v, c) for( typeof( (c).begin()) v = (c).begin(); v != (c).end(); ++v)
#define all(a) a.begin(), a.end()
#define in(a,b) ( (b).find(a) != (b).end())
#define pb push_back
#define fill(a,v) memset(a, v, sizeof a)
#define sz(a) ((int)(a.size()))
#define mp make_pair
using namespace std;
const string ops[] = {
";",
",",
// data types
"int",
"float",
"string",
"double",
"long",
"long long",
// control flow
"if",
"else",
"switch",
"case",
"do",
"while",
"for",
// encapsulation
"(",
"{",
"[",
// member access
".",
"->",
// arithmetic
"+",
"-",
"*",
"/",
"%",
"=",
"++",
"--",
// logical
"<",
">",
"<=",
">=",
"==",
// keywords
"break",
"continue",
"class",
"struct",
"default",
"goto",
"operator",
"return"
};
set<string> operators;
map<string, int> operator_counts, operand_counts;
class redundancy_pair
{
public:
string f,s;
int multiplicity;
redundancy_pair( string a, string b, int multiplicity )
{
this->f = a, this->s = b, this->multiplicity = multiplicity;
}
};
// redundancy pairs are necessary to remove matches that match multiple
// patterns for example c++ matches both '++' and '+', multiplicity is
// required to make adjustments to the count variables
vector <redundancy_pair> redundancy_pairs;
void _popualate_redundancy_pairs()
{
for ( set<string>::iterator i = operators.begin(); i != operators.end(); i++)
{
for ( set<string>::iterator j = operators.begin(); j != operators.end(); j++ )
{
if ( (*i) != (*j) )
{
// find num occurences in strings
int num_occur = 0 , pos = 0;
while ( (pos = (*i).find(*j, pos)) != string::npos )
{
num_occur++;
pos += (*j).length();
}
if ( num_occur > 0 )
redundancy_pairs.push_back( redundancy_pair( *j , *i , num_occur ) );
}
}
}
}
void _popualate_operators ()
{
int size = *(&ops + 1) - ops;
for ( int i=0 ; i < size; i++ )
operators.insert( ops[i] );
}
void _adjust_redundancy()
{
for ( vector<redundancy_pair>::iterator it = redundancy_pairs.begin(); it != redundancy_pairs.end(); it++ )
{
// second exists
if ( operator_counts.find( (*it).s ) != operator_counts.end())
operator_counts[(*it).f] = operator_counts[(*it).f] - operator_counts[(*it).s]*((*it).multiplicity);
}
return;
}
int main()
{
// fill the operators
_popualate_operators();
_popualate_redundancy_pairs();
// we now create a regex for identifier
regex identifier_def( "[A-Za-z][A-Za-z0-9]*" );
// numbers defined at word boundary , important condition
// for matching numbers is that they have to be separated by
// word boundaries
regex number_def( "\\b([0-9]+)\\b" );
smatch sm;
ifstream file( "code.txt" );
string input;
if ( file.is_open() )
{
while ( getline( file, input ) )
{
// now check for operators in the line
for ( set<string>::iterator op = operators.begin(); op != operators.end(); op++)
{
int pos = 0;
// for every operator scan the entire line for multiple matches
while (( pos = input.find( *op, pos )) != string::npos)
{
// found an operator
if ( operator_counts.find( *op ) == operator_counts.end() )
operator_counts.insert({ *op, 1 });
else
operator_counts[*op]++;
pos += (*op).length();
}
}
// now lets check for identifiers
string::const_iterator pos( input.cbegin() );
while( regex_search (pos, input.cend(), sm , identifier_def))
{
// check if identifier is an operator
if ( operators.find( sm[0] ) != operators.end() )
{
pos += sm.position() + sm.length();
continue;
}
string operand = sm[0];
// if not add to map
if ( operand_counts.find( operand ) != operand_counts.end() )
operand_counts[operand]++;
else
operand_counts.insert( make_pair( operand, 1 ) );
pos += sm.position() + sm.length();
}
// search for numbers
pos = input.cbegin();
while ( regex_search( pos, input.cend(), sm, number_def ) )
{
// check if identifier is an operator
if ( operators.find( sm[0] ) != operators.end() )
{
pos += sm.position() + sm.length();
continue;
}
string operand = sm[0];
// cout << "Operand : " << operand << endl;
// if not add to map
if ( operand_counts.find( operand ) != operand_counts.end() )
operand_counts[operand]++;
else
operand_counts.insert( make_pair( operand, 1 ) );
pos += sm.position() + sm.length();
}
}
_adjust_redundancy();
}
int N1=0,n1=0,n2=0,N2=0;
for ( map<string, int>::iterator it=operator_counts.begin(); it != operator_counts.end(); it++ )
{
if ( (*it).second ) n1++;
N1 += (*it).second;
}
for ( map<string, int>::iterator it=operand_counts.begin(); it != operand_counts.end(); it++ )
{
if( (*it).second ) n2++;
N2 += (*it).second;
}
printf("n1:%d, n2:%d, N1:%d, N2:%d\n", n1, n2 , N1, N2);
// compute the halstead metrics now
// program size defined as the sum of
// all operands and operators
int size = N1 + N2;
// Vocabulary size -- Size of the vocabulary
// defined as sum of distinct operands and operators
int vocab_size = n1+n2;
// Volume - Program Volume , defined as follows:
// Volume = size x log ( vocab_size )
double volume = size*log2(vocab_size);
// Difficulty = ( n1/2 ) x ( N2/n2 ) and level = 1/difficulty
double difficulty = (double(n1)/2) * (double(N2)/double(n2));
double level = (1/difficulty);
// effort = volume x difficulty
double effort = volume*difficulty;
cout << "Size : " << size << endl;
cout << "Vocabulary Size : " << vocab_size << endl;
cout << "volume : " << volume << endl;
cout << "difficulty : " << difficulty << endl;
cout << "level : " << level << endl;
cout << "effort : " << effort << endl;
}
For a beginner it's really hard to modify this code, I just want to know which part, I need to look in order to display operators and operands

AddressSanitizer throwing SEGV on unknown address C++

I have a task where I have to make a class depending on std::multiset. The idea is that it gets 2 multisets in its constructor, they then have to be sorted and put back in those variables while the class is in scope.To provide an example:
std::multiset<int> a;
std::multiset<int> b;
a.insert(4); a.insert(3); a.insert(1); a.insert(10); // a={1,3,4,10}
b.insert(3); b.insert(2); // b={2,3}
if(true){
multisets_merge_view<int>(a,b);
// sorts them and makes it, so that:
// a={1,2,3,3}
// b={4,10}
}
// and here, the multisets need to go back to their original state:
// a={1,3,4,10}
// b={2,3}
We have to work with g++ 9.3.0 under Ubuntu 20.04, with the following flags: -fsanitize=address,leak,undefined -O3 -Wall -Wextra -WerrorThe code - that was given and I cannot touch - to check if everything works correctly:
#include <iostream>
#include <numeric>
#include "msmview.h"
#include <set>
#include <iterator>
#include <string>
#include <algorithm>
#include "msmview.h"
struct string_size_less
{
bool operator()( const std::string& lhs,
const std::string& rhs ) const
{
return lhs.size() < rhs.size();
}
};
const int max = 1000;
bool check()
{
std::multiset<int> a;
std::multiset<int> b;
a.insert( 1 );
a.insert( 7 );
a.insert( 4 );
b.insert( 4 );
b.insert( 3 );
std::multiset<std::string> s;
std::multiset<std::string> t;
s.insert( "C++" );
s.insert( "Pascal" );
s.insert( "Haskell" );
t.insert( "C" );
t.insert( "Ada" );
std::multiset<int> x;
std::multiset<int> y;
for( int i = 0 ; i < max; ++i )
{
x.insert( i );
y.insert( i );
}
bool c = x.count( max / 3 ) == 2;
if ( !c )
{
multisets_merge_view<int> mvi( a, b );
multisets_merge_view<int> mvm( x, y );
multisets_merge_view<std::string> mvs( s, t );
c = x.count( max / 3 ) == 2 && 3 == s.size() &&
0 == s.count( "Pascal" ) && 1 == t.count( "Pascal" ) &&
0 == x.count( max - 1 ) && 1 == s.count( "C" ) &&
0 == a.count( 7 ) && 0 == b.count( 3 );
}
if ( !c || 1 != x.count( max / 3 ) || 1 != s.count( "Pascal" ) ||
0 != s.count( "C" ) || 2 != t.size() || 1 != x.count( max - 1 ) ||
1 != a.count( 7 ) || 1 != b.count( 3 ) )
{
return false;
}
if ( c )
{
const multisets_merge_view<int> mvi( a, b );
const multisets_merge_view<int> mvm( x, y );
const multisets_merge_view<std::string> mvs( s, t );
if ( 5 != mvi.size() || 2 != mvi.count( 4 ) || 0 != mvi.count( max ) ||
5 != mvs.size() || 1 != mvs.count( "C++" ) || 2 * max != mvm.size() ){
return false;
}
}
else
{
std::cout << "neither";
return false;
}
std::multiset<int, std::greater<int> > ga;
std::multiset<int, std::greater<int> > gb;
ga.insert( 0 );
ga.insert( max );
gb.insert( max );
std::multiset<std::string, string_size_less> sa;
std::multiset<std::string, string_size_less> sb;
sa.insert( "C++" );
sa.insert( "Haskell" );
sb.insert( "Ada" );
sb.insert( "SQL" );
sb.insert( "LISP" );
if ( c )
{
const multisets_merge_view<std::string, string_size_less> mvs( sa, sb );
const multisets_merge_view<int, std::greater<int> > mvi( ga, gb );
return 2 == sa.count( "C++" ) && 1 == sb.count( "C++" ) && 1 == gb.count( 0 ) &&
3U == sb.size() && ga.size() == ga.count( max ) && 3 == mvi.size();
}
return false;
}
int main()
{
std::cout
<< "Your solution is "
<< (check() ? "" : "not ")
<< "ready for submission."
<< std::endl;
}
And my code for the upper mentioned class:
#ifndef MSMVIEW_H
#define MSMVIEW_H
#include <set>
template<typename T1, typename T2 = std::greater<T1>>
class multisets_merge_view : public std::multiset<T1,T2>{
public:
multisets_merge_view(std::multiset<T1> &a, std::multiset<T1> &b);
multisets_merge_view(std::multiset<T1,T2> &a, std::multiset<T1,T2> &b);
~multisets_merge_view();
int size() const { return _size; }
int count(T1 t) const;
private:
std::multiset<T1> *_apo;
std::multiset<T1> *_bpo;
std::multiset<T1,T2> *_apt;
std::multiset<T1,T2> *_bpt;
std::multiset<T1> _ao;
std::multiset<T1> _bo;
std::multiset<T1,T2> _at;
std::multiset<T1,T2> _bt;
unsigned int _size;
};
template<typename T1, typename T2>
multisets_merge_view<T1,T2>::multisets_merge_view(std::multiset<T1> &a, std::multiset<T1> &b):_ao(a),_bo(b),_size(a.size()+b.size()){
_apo = &a;
_bpo = &b;
std::multiset<T1> tmp;
tmp.insert(a.begin(),a.end());
tmp.insert(b.begin(),b.end());
a.clear();
b.clear();
for(typename std::multiset<T1>::const_iterator i(tmp.begin()),end(tmp.end()); i!=end; ++i){
if(a.size() < _ao.size()){
a.insert(*i);
}else{
b.insert(*i);
}
}
};
template<typename T1, typename T2>
multisets_merge_view<T1,T2>::multisets_merge_view(std::multiset<T1,T2> &a, std::multiset<T1,T2> &b):_at(a),_bt(b),_size(a.size()+b.size()){
_apt = &a;
_bpt = &b;
std::multiset<T1,T2> tmp;
tmp.insert(a.begin(),a.end());
tmp.insert(b.begin(),b.end());
a.clear();
b.clear();
for(typename std::multiset<T1,T2>::const_iterator i(tmp.begin()),end(tmp.end()); i!=end; ++i){
if(a.size() < _at.size()){
a.insert(*i);
}else{
b.insert(*i);
}
}
};
template<typename T1, typename T2>
multisets_merge_view<T1,T2>::~multisets_merge_view(){
if(_apo != nullptr && _bpo != nullptr){
*_apo = _ao;
*_bpo = _bo;
}else if(_apt != nullptr && _bpt != nullptr){
*_apt = _bt;
*_bpt = _at;
}
};
template<typename T1, typename T2>
int multisets_merge_view<T1,T2>::count(T1 t) const{
int count = 0;
if(_apo != nullptr && _bpo != nullptr){
for(typename std::multiset<T1>::const_iterator i = _ao.begin(); i != _ao.end(); i++){
if(*i==t) count++;
}
for(typename std::multiset<T1>::const_iterator i = _bo.begin(); i != _bo.end(); i++){
if(*i==t) count++;
}
}else if(_apt != nullptr && _bpt != nullptr){
for(typename std::multiset<T1,T2>::const_iterator i = _at.begin(); i != _at.end(); i++){
if(*i==t) count++;
}
for(typename std::multiset<T1,T2>::const_iterator i = _bt.begin(); i != _bt.end(); i++){
if(*i==t) count++;
}
}
return count;
};
#endif
When I run the compiler, AddressSanitizer throws a memory reallocation error found in ~multisets_merge_view(), probably when *_apt=_at; *_bpt=_bt; happens (without providing a second template parameter in the main program, everything works fine, but as I said I can't modify that).
Is there a way to fix this while not touching the main program and still using the -fsanitize=address,leak,undefined?

HashTable... error: static assertion failed: std::hash is not specialized for this type

I posted earlier today and was able to work out a lot of my errors. However, I still have one error that I cannot figure out for the life of me. I'm basically just trying to insert a Symbol object into a HashTable and I'm constantly getting this message back:
In file included from /opt/local/include/gcc47/c++/bits/basic_string.h:3032:0,
from /opt/local/include/gcc47/c++/string:54,
from /opt/local/include/gcc47/c++/bits/locale_classes.h:42,
from /opt/local/include/gcc47/c++/bits/ios_base.h:43,
from /opt/local/include/gcc47/c++/ios:43,
from /opt/local/include/gcc47/c++/ostream:40,
from /opt/local/include/gcc47/c++/iostream:40,
from Driver.cpp:1:
/opt/local/include/gcc47/c++/bits/functional_hash.h: In instantiation of 'struct std::hash<Symbol>':
SeparateChaining.h:143:33: required from 'size_t HashTable<HashedObj>::myhash(const HashedObj&) const [with HashedObj = Symbol; size_t = long unsigned int]'
SeparateChaining.h:56:51: required from 'bool HashTable<HashedObj>::insert(HashedObj&) [with HashedObj = Symbol]'
Driver.cpp:135:26: required from here
/opt/local/include/gcc47/c++/bits/functional_hash.h:60:7: error: static assertion failed: std::hash is not specialized for this type
More specifically though.... The error:
error: static assertion failed: std::hash is not specialized for this type
Here is my Driver.cpp file:
#include <iostream>
#include <iomanip>
#include <cassert>
#include <fstream>
#include <string>
#include <vector>
#include <time.h>
#include <unistd.h>
#include <map>
#include <cstdlib>
#include <cmath>
#include "SeparateChaining.h"
using namespace std;
int TABLE_SIZE; //I know it's a global, but it allows the Table Size to be taken in within main() and used in hash()
size_t hash(const string & key);
class Symbol
{
private:
int key;
int type;
string data;
public:
const string & getData() const
{
return data;
}
int getType()
{
return type;
}
int getKey()
{
return labs(key);
}
void setType(int Type)
{
type = Type;
}
void setData(string Data)
{
data = Data;
}
void setKey(int Key)
{
key = Key;
}
bool operator== (const Symbol & rhs) const
{
return getData() == rhs.getData();
}
bool operator!= (const Symbol & rhs) const
{
return !(*this == rhs);
}
};
int main()
{
HashTable<Symbol> hashtable(TABLE_SIZE);
Symbol temp;
vector<Symbol> symbols;
string s;
int t;
int hash_key_array[TABLE_SIZE]; //array to hold hash key values
ifstream file;
file.open("symbols.txt");
if(!file)
{
cout << "System failed to open file.";
}
else
{
cout << "File successfully opened" << endl;
}
//for loop to read in the string name and the integer that follows the string name from symbols.txt
while(file >> s)
{
temp.setData(s);
file >> t;
temp.setType(t);
symbols.push_back(temp);
}
for(int i = 0; i < symbols.size(); i++)
{
cout << symbols[i].getData() << "\n";
cout << symbols[i].getType() << "\n";
}
cout << "What would you like the table size to be?" << endl;
cout << "Note: If the table size is greater than the number of objects" <<
" in the symbols.txt file, it will inevitably throw a segmentation fault" << endl;
cin >> TABLE_SIZE;
for(int j = 0; j < TABLE_SIZE; j++)
{
temp.setData(symbols[j].getData());
cout << temp.getData() << endl;
temp.setType(symbols[j].getType());
cout << temp.getType() << endl;
temp.setKey(::hash(symbols[j].getData()));
cout << "The key is: " << temp.getKey() << endl;
cout << endl;
hash_key_array[j] = temp.getKey();
for (int i = 0; i < TABLE_SIZE; i++)
{
if (i != j)
{
if (hash_key_array[i] == hash_key_array[j])
{
cout << endl;
cout << "Collision occurred at " << hash_key_array[i] << endl;
//rehash();
//cout << "The new key is: " << temp.getKey() << endl;
break;
}
}
}
hashtable.insert(temp);
}
}
size_t hash(const string & key)
{
size_t hashVal = 0;
for(char ch : key)
{
hashVal = 37 * hashVal + ch;
}
return labs(hashVal);
}
And my Header File.... SeperateChaining.h:
#ifndef SEPARATE_CHAINING_H
#define SEPARATE_CHAINING_H
#include <vector>
#include <list>
#include <string>
#include <algorithm>
#include <functional>
//#include "Hash.h"
using namespace std;
// SeparateChaining Hash table class
//
// CONSTRUCTION: an approximate initial size or default of 101
//
// ******************PUBLIC OPERATIONS*********************
// bool insert( x ) --> Insert x
// bool remove( x ) --> Remove x
// bool contains( x ) --> Return true if x is present
// void makeEmpty( ) --> Remove all items
int nextPrime( int n );
bool isPrime( int n );
template <typename HashedObj>
class HashTable
{
public:
//Uses the whatever value table_size has
//Otherwise, it will make a hash table of size 101
explicit HashTable( int TABLE_SIZE )
{
currentSize = 0;
theLists.resize(TABLE_SIZE);
}
bool contains( const HashedObj & x ) const
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[ myhash( x ) ];
//returns whatever you wanted to search for in the table provided it is there
return find( begin( whichList ), end( whichList ), x ) != end( whichList );
}
void makeEmpty( )
{
for( auto & thisList : theLists )
thisList.clear( );
}
bool insert(HashedObj & temp )
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[myhash( temp )];
//goes through the beginning and end of the list, and if it
//doesn't get to the end, then it found the object you wanted to insert in the hash table already
//prevents duplicate insertions
if( find( begin( whichList ), end( whichList ), temp ) != end( whichList) )
return false;
//otherwise, it has gotten to the end of the list without finding a duplicate
//and puts what you want to insert in the list
whichList.push_back( temp );
// Rehash; see Section 5.5
if( ++currentSize > theLists.size( ) )
rehash( );
return true;
}
bool insert(const HashedObj && x )
{
auto & whichList = theLists[ myhash( x ) ];
if( find( begin( whichList ), end( whichList ), x ) != end( whichList ) )
return false;
whichList.push_back( std::move( x ) );
// Rehash; see Section 5.5
if( ++currentSize > theLists.size( ) )
rehash( );
return true;
}
bool remove( const HashedObj & x )
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[ myhash( x ) ];
//trying to find x within the list
//the iterator points to the slot in the list that contains x
auto itr = find( begin( whichList ), end( whichList ), x );
//if it gets to the end of the list without finding what you want to remove, then it returns false
if( itr == end( whichList ) )
{
return false;
}
//if it finds x, it removes it from the list
whichList.erase( itr );
--currentSize;
return true;
}
/*
void printTable()
{
for(int i=0; i < symbols.size(); i++)
{
cout << "The hash table contains: " << symbols[i] << endl;
}
}
*/
private:
vector<list<HashedObj>> theLists; // The array of Lists
int currentSize;
void rehash( )
{
vector<list<HashedObj>> oldLists = theLists;
// Creates new double-sized, empty table
theLists.resize( nextPrime( 2 * theLists.size( ) ) );
for( auto & thisList : theLists )
thisList.clear( );
// Copies the old table into the new table
currentSize = 0;
for( auto & thisList : oldLists )
for( auto & x : thisList )
insert( std::move( x ) );
}
size_t myhash( const HashedObj & x ) const
{
static hash<HashedObj> hf;
return hf( x ) % theLists.size( );
}
};
int nextPrime( int n )
{
if( n % 2 == 0 )
{
++n;
}
for( ; !isPrime( n ); n += 2 )
{
}
return n;
}
bool isPrime( int n )
{
if( n == 2 || n == 3 )
return true;
if( n == 1 || n % 2 == 0 )
return false;
for( int i = 3; i * i <= n; i += 2 )
if( n % i == 0 )
return false;
return true;
}
#endif
I would really appreciate you guys helping me out!
You are doing this:
static hash<HashedObj> hf;
but you have not provided a hash template, or have not specialized std::hash for HashedObj.
You should avoid using namespace std;. Amongst other things, it is difficult to figure out which hash you want to get.

Similar function in C++ to Python's strip()?

There is a very useful function in Python called strip(). Any similar ones in C++?
I use this:
#include <string>
#include <cctype>
std::string strip(const std::string &inpt)
{
auto start_it = inpt.begin();
auto end_it = inpt.rbegin();
while (std::isspace(*start_it))
++start_it;
while (std::isspace(*end_it))
++end_it;
return std::string(start_it, end_it.base());
}
There's nothing built-in; I used to use something like the following:
template <std::ctype_base::mask mask>
class IsNot
{
std::locale myLocale; // To ensure lifetime of facet...
std::ctype<char> const* myCType;
public:
IsNot( std::locale const& l = std::locale() )
: myLocale( l )
, myCType( &std::use_facet<std::ctype<char> >( l ) )
{
}
bool operator()( char ch ) const
{
return ! myCType->is( mask, ch );
}
};
typedef IsNot<std::ctype_base::space> IsNotSpace;
std::string
trim( std::string const& original )
{
std::string::const_iterator right = std::find_if( original.rbegin(), original.rend(), IsNotSpace() ).base();
std::string::const_iterator left = std::find_if(original.begin(), right, IsNotSpace() );
return std::string( left, right );
}
which works pretty well. (I now have a significantly more complex
version which handles UTF-8 correctly.)
void strip(std::string &str)
{
if (str.length() != 0)
{
auto w = std::string(" ") ;
auto n = std::string("\n") ;
auto r = std::string("\t") ;
auto t = std::string("\r") ;
auto v = std::string(1 ,str.front());
while((v == w) || (v==t) || (v==r) || (v==n))
{
str.erase(str.begin());
v = std::string(1 ,str.front());
}
v = std::string(1 , str.back());
while((v ==w) || (v==t) || (v==r) || (v==n))
{
str.erase(str.end() - 1 );
v = std::string(1 , str.back());
}
}
This is on top of the answer provided by Ferdi Kedef to make it safer.
void strip(std::string& str)
{
if (str.length() == 0) {
return;
}
auto start_it = str.begin();
auto end_it = str.rbegin();
while (std::isspace(*start_it)) {
++start_it;
if (start_it == str.end()) break;
}
while (std::isspace(*end_it)) {
++end_it;
if (end_it == str.rend()) break;
}
int start_pos = start_it - str.begin();
int end_pos = end_it.base() - str.begin();
str = start_pos <= end_pos ? std::string(start_it, end_it.base()) : "";
}

C++ Graph Building Question

Hello I want to build a graph for connecting sentences.
for example my files has following lines.
ab cd ef
ef gh ij
ij kl mn
xy ab cd
So I want each node should have one line i.e. ab cd ef should be one node and it should be connected to ef gh ij which should be connected to ij kl mn.
Basically last word of a line should be connect to any line whose first word matches with last word.
Here is what I have come up so far, but failing when I add Edges.
#include <map>
#include <string>
#include <deque>
#include <list>
#include <iostream>
#include <stack>
#include <fstream>
#include <vector>
class GraphNode {
public:
GraphNode(std::string name) {
std::vector<std::string> words;
std::string::size_type lastPos = name.find_first_not_of(' ', 0);
std::string::size_type pos = name.find_first_of(' ', lastPos);
while (std::string::npos != pos || std::string::npos != lastPos){
words.push_back(name.substr(lastPos, pos - lastPos));
lastPos = name.find_first_not_of(' ', pos);
pos = name.find_first_of(' ', lastPos);
}
first = words[0];
middle = " ";
for ( int i = 1; i < (int)words.size() - 1; i++) {
middle = words[i] + " ";
}
last = words[words.size() - 1 ];
}
~GraphNode() {};
std::string first;
std::string middle;
std::string last;
};
struct GraphNodeCompare {
bool operator() (const GraphNode& lhs, const GraphNode& rhs) {
return lhs.last < rhs.last;
}
};
class Graph {
public:
Graph() {}
~Graph() {}
typedef std::map <GraphNode, std::list<GraphNode>, GraphNodeCompare > GraphType;
void AddVertex ( GraphNode vertexID );
void AddEdge ( GraphNode vertexLeft, GraphNode vertexRight);
std::list<GraphNode> GetVertices(GraphNode vertexID);
friend std::ostream& operator << (std::ostream& os, const Graph& dt);
private:
GraphType m_graph;
protected:
};
void Graph::AddVertex(GraphNode vertexID) {
GraphType::const_iterator iter = m_graph.find(vertexID);
if ( iter == m_graph.end()) {
std::list<GraphNode> list;
m_graph[vertexID] = list;
}
}
void Graph::AddEdge( GraphNode vertexLeft, GraphNode vertexRight) {
AddVertex(vertexLeft);
AddVertex(vertexRight);
m_graph[vertexLeft].push_back(vertexRight);
m_graph[vertexRight].push_back(vertexLeft);
}
std::list<GraphNode> Graph::GetVertices(GraphNode vertexID) {
GraphType::const_iterator iter = m_graph.find(vertexID);
std::list<GraphNode> list;
if ( iter != m_graph.end()){
return m_graph[vertexID];
}
return list;
}
std::ostream& operator << (std::ostream& os, const Graph& graph) {
std::cout << "---------------------------------------------" << std::endl;
std::map<GraphNode, std::list<GraphNode>, GraphNodeCompare >::const_iterator iter;
for ( iter = graph.m_graph.begin(); iter != graph.m_graph.end(); ++iter) {
std::cout << iter->first.first << iter->first.middle << iter->first.last << " : " ;
std::list<GraphNode> list = iter->second;
std::list<GraphNode>::const_iterator iter1;
for ( iter1 = list.begin(); iter1 != list.end(); ++iter1) {
std::cout << iter1->first << iter1->middle << iter1->last << '\t' ;
}
std::cout << std::endl;
}
std::cout << "---------------------------------------------" << std::endl;
return os;
}
int main( int argc, char **argv) {
Graph *pGraph = new Graph();
std::ifstream dataFile("D:\\personal\\data\\datas3.txt");
if ( dataFile.peek() == EOF ) {
return -1;
}
if (dataFile.is_open()) {
while (! dataFile.eof() ) {
std::string line;
std::getline (dataFile,line);
GraphNode node(line);
pGraph->AddVertex(node);
std::list<GraphNode> vertices = pGraph->GetVertices(node);
for ( std::list<GraphNode>::iterator itr = vertices.begin(); itr != vertices.end(); ++itr) {
pGraph->AddEdge( node, *itr);
}
//std::cout << line << std::endl;
}
}
dataFile.close();
//std::cout << *pGraph;
delete pGraph;
}
I can suggest this tiny, non object-oriented implementation. Works fine for you problem:
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <string>
typedef std::vector< std::string > Node;
typedef std::pair< int, int > Edge;
// Node stuff
std::string firstWord ( const Node& node ) { return *node.begin(); }
std::string lastWord ( const Node& node ) { return *node.rbegin(); }
void addWord ( Node& node, std::string s ) { node.push_back( s ); }
bool isNotEmpty( const Node& node ) { return !node.empty(); }
bool precedes( const Node& a, const Node& b ) { return lastWord( a ) == firstWord( b ); }
struct Graph
{
void addNode ( const Node& node ) { nodes.push_back( node ); }
void addEdge ( const int& from, const int& to ) { edges.push_back( Edge( from, to ) ); }
std::vector< Edge > edges;
std::vector< Node > nodes;
};
std::ostream& operator << ( std::ostream& out, const Graph& graph )
{
int esize = graph.edges.size();
for( int i = 0; i < esize; ++i )
{
int index1 = graph.edges[ i ].first, index2 = graph.edges[ i ].second;
for( int j = 0; j < graph.nodes[ index1 ].size(); ++j )
out << graph.nodes[ index1 ][ j ] << ' ';
out << "----> ";
for( int j = 0; j < graph.nodes[ index2 ].size(); ++j )
out << graph.nodes[ index2 ][ j ] << ' ';
out << std::endl;
}
return out;
}
int main ()
{
Graph graph;
std::ifstream inputFile( "input.txt" );
std::string s;
// reading from file and constructing graph vertices
if( inputFile.is_open() )
while( !inputFile.eof() )
{
std::getline( inputFile, s );
std::stringstream ss( s );
Node node;
while( ss >> s )
addWord( node, s );
if( isNotEmpty( node ) )
graph.addNode( node );
}
inputFile.close();
// constructing graph edges
std::vector< Node > nodes ( graph.nodes );
int sz = nodes.size();
for( int i = 0; i < sz; ++i )
for( int j = 0; j < sz; ++j )
if( precedes( nodes[ i ], nodes[ j ] ) )
graph.addEdge( i, j );
// let's see what we got
std::cout << graph;
return 0;
}
Also, as #spraff says, if you want to use a well-designed graph library, have a look at Boost.
Have you considered one of the excellent Boost libraries?