File: stringtable.h

package info (click to toggle)
systemtap 5.1-5
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 47,964 kB
  • sloc: cpp: 80,838; ansic: 54,757; xml: 49,725; exp: 43,665; sh: 11,527; python: 5,003; perl: 2,252; tcl: 1,312; makefile: 1,006; javascript: 149; lisp: 105; awk: 101; asm: 91; java: 70; sed: 16
file content (178 lines) | stat: -rw-r--r-- 5,814 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// -*- C++ -*-
// Copyright (C) 2015 Red Hat Inc.
//
// This file is part of systemtap, and is free software.  You can
// redistribute it and/or modify it under the terms of the GNU General
// Public License (GPL); either version 2, or (at your option) any
// later version.


#ifndef STRINGTABLE_H
#define STRINGTABLE_H

#include <functional>
#include <string>
#include <cstring>

// TODO use C++17's std::string_view when possible.  It even hashes natively.
// (some compilers already have std::experimental::string_view)

#if defined(HAVE_BOOST_UTILITY_STRING_REF_HPP)
#include <boost/version.hpp>
#include <boost/utility/string_ref.hpp> //header with string_ref

// XXX: experimental tunables
#define INTERNED_STRING_FIND_MEMMEM 1 /* perf stat indicates a very slight benefit */
#define INTERNED_STRING_CUSTOM_HASH 1 /* maybe an abbreviated hash function for long strings? */
#define INTERNED_STRING_INSTRUMENT 0 /* write out hash logs ... super super slow */

struct interned_string: public boost::string_ref
{
  // all these construction operations intern the incoming string
  interned_string(): boost::string_ref() {}
  interned_string(const char* value):
    boost::string_ref(intern(value)) {}
  interned_string(const std::string& value):
    boost::string_ref(intern(value)) {}
  interned_string& operator = (const std::string& value)
    { return *this = intern(value); }
  interned_string& operator = (const char* value)
    { return *this = intern(value); }

#if BOOST_VERSION < 105400
  std::string to_string () const { return std::string(this->data(), this->size()); }

  // some comparison operators that aren't available in boost 1.53
  bool operator == (const char* y) { return compare(boost::string_ref(y)) == 0; }
  bool operator == (const std::string& y) { return compare(boost::string_ref(y)) == 0; }
  friend bool operator == (interned_string x, interned_string y) { return x.compare(y) == 0; }
  friend  bool operator == (const char * x, interned_string y)
  {
    return y.compare(boost::string_ref(x)) == 0;
  }
  friend bool operator == (const std::string& x, interned_string y)
  {
    return y.compare(boost::string_ref(x)) == 0;
  }

  bool operator != (const char* y) { return compare(boost::string_ref(y)) != 0; }
  bool operator != (const std::string& y) { return compare(boost::string_ref(y)) != 0; }
  friend bool operator != (interned_string x, interned_string y) { return x.compare(y) != 0; }
  friend  bool operator != (const char * x, interned_string y)
  {
    return y.compare(boost::string_ref(x)) != 0;
  }
  friend bool operator != (const std::string& x, interned_string y)
  {
    return y.compare(boost::string_ref(x)) != 0;
  }
#endif

  // easy out-conversion operators
  operator std::string () const { return this->to_string(); }

  // return an efficient substring reference
  interned_string substr(size_t pos = 0, size_t len = npos) const
  {
    return boost::string_ref::substr(pos, len);
  }

  // boost oversights
  template <typename F>
  size_t find (const F& f, size_t start_pos)
  {
    size_t x = this->substr(start_pos).find(f);
    if (x == boost::string_ref::npos)
      return x;
    else
      return x + start_pos;
  }
  
  template <typename F>
  size_t find (const F& f) const
  {
    return boost::string_ref::find(f);
  }
  
#if INTERNED_STRING_FIND_MEMMEM
  size_t find (const boost::string_ref& f) const;
  size_t find (const std::string& f) const;
  size_t find (const char *f) const;
#endif

  size_t find (const interned_string& f) const
  {
    return find (static_cast<const boost::string_ref&> (f));
  }
  
private:
  static interned_string intern(const std::string& value);
  static interned_string intern(const char* value);
  static interned_string intern(char value);

  // This is private so we can be sure of ownership, from our interned string table.
  interned_string(const boost::string_ref& value): boost::string_ref(value) {}
};

namespace std {
  template<> struct hash<interned_string> {
    size_t operator() (interned_string s) const
    {
      // NB: we'd love to be able to hook up to a blob hashing
      // function in std::hash, but there isn't one.  We don't want
      // to copy the interned_string into a temporary string just to
      // hash the thing.
      //
      // This code is based on the g++ _Fnv_hash_base ptr/length case.
      size_t hash = 0;
      const char* x = s.data();
      for (size_t i=s.length(); i>0; i--)
        hash = (hash * 131) + *x++;
      return hash;
    }
  };
}

#else /* !defined(HAVE_BOOST_UTILITY_STRING_REF_HPP) */

struct interned_string : public std::string {
  interned_string(): std::string() {}
  interned_string(const char* value): std::string (value ? :"") {}
  interned_string(const std::string& value): std::string(value) {}
  std::string to_string() const {return (std::string) *this; }
  void remove_prefix (size_t n) {*this = this->substr(n);}
  interned_string substr(size_t pos = 0, size_t len = npos) const
  {
    return (interned_string)std::string::substr(pos, len);
  }
  bool starts_with(const char* value) const
  {
    return (this->compare(0, std::strlen(value), value) == 0);
  }

  bool starts_with(const std::string& value) const
  {
    return (this->compare(0, value.length(), value) == 0);
  }

private:
  // c_str is not allowed on boost::string_ref, so add a private unimplemented
  // declaration here to prevent the use of string::c_str accidentally.
  const char* c_str() const;
};

namespace std {
  template<> struct hash<interned_string> {
    size_t operator() (interned_string const& s) const
    {
      // strings are directly hashable
      return hash<string>()(s);
    }
  };
}

#endif /* defined(HAVE_BOOST_UTILITY_STRING_REF_HPP) */

#endif // STRINGTABLE_H

/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */