randomgenerator.cpp 5.46 KB
Newer Older
Giorgio Azzinnaro's avatar
Giorgio Azzinnaro committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * ProfaneDB - A Protocol Buffers database.
 * Copyright (C) 2017  "Giorgio Azzinnaro" <giorgio.azzinnaro@gmail.com>
 *
 * This program 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.
 *
 * This program 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "randomgenerator.h"

22
using boost::random::mt19937;
Giorgio Azzinnaro's avatar
Giorgio Azzinnaro committed
23
24
25
26
27
28
29
30
31
32
33
34
35
using boost::random::uniform_int_distribution;
using boost::random::uniform_real_distribution;

using google::protobuf::Message;
using google::protobuf::Descriptor;
using google::protobuf::FieldDescriptor;
using google::protobuf::Reflection;

using std::numeric_limits;

namespace profanedb {
namespace util {

36
37
RandomGenerator::RandomGenerator(mt19937 & gen)
  : gen(gen)
Giorgio Azzinnaro's avatar
Giorgio Azzinnaro committed
38
39
40
41
42
43
44
{
}

#define RANDOM_VALUE(TYPE, BODY) template<> TYPE RandomGenerator::RandomValue< TYPE >() { BODY }
#define INT_RANDOM_VALUE(TYPE) RANDOM_VALUE(TYPE, \
    uniform_int_distribution< TYPE > range(       \
        numeric_limits< TYPE >::min(),            \
45
46
        numeric_limits< TYPE >::max());           \
    return range(this->gen);                      )
Giorgio Azzinnaro's avatar
Giorgio Azzinnaro committed
47
48
49
50
51
52
53
54

INT_RANDOM_VALUE(google::protobuf::int32);
INT_RANDOM_VALUE(google::protobuf::int64);
INT_RANDOM_VALUE(google::protobuf::uint32);
INT_RANDOM_VALUE(google::protobuf::uint64);

#undef INT_RANDOM_VALUE

55
56
57
58
59
60
61
62
63
64
65
#define REAL_RANDOM_VALUE(TYPE) RANDOM_VALUE(TYPE, \
    uniform_real_distribution<> range(             \
        numeric_limits< TYPE >::min(),             \
        numeric_limits< TYPE >::max());            \
    return range(this->gen);                       )

REAL_RANDOM_VALUE(double);
REAL_RANDOM_VALUE(float);

#undef REAL_RANDOM_VALUE

Giorgio Azzinnaro's avatar
Giorgio Azzinnaro committed
66
RANDOM_VALUE(google::protobuf::string,
67
68
69
70
71
72
73
74
75
76
77
78
79
    std::string random;         
    std::string chars(
        "abcdefghijklmnopqrstuvwxyz"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "1234567890"
        "!@#$%^&*()"
        "`~-_=+[{]}\\|;:'\",<.>/? ");
    
    uniform_int_distribution<> index_dist(0, chars.size() - 1);
    for(int i = 0; i < this->RandomValue<uint>(); i++)
        random += chars[index_dist(gen)];
        
    return random;
Giorgio Azzinnaro's avatar
Giorgio Azzinnaro committed
80
81
82
)

RANDOM_VALUE(bool,
83
84
    uniform_int_distribution<> range(0, 1);
    return (bool) range(this->gen);
Giorgio Azzinnaro's avatar
Giorgio Azzinnaro committed
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
)
#undef RANDOM_VALUE

void RandomGenerator::FillRandomly(Message * message)
{
    // Descriptor is used to iterate through the existing fields
    const Descriptor * descriptor = message->GetDescriptor();
    
    // Reflection is used to set the values without knowing the types at compile time
    const Reflection * reflection = message->GetReflection();
    
    for(int i = 0; i < descriptor->field_count(); i++) {
        const FieldDescriptor * fd = descriptor->field(i);
        
        // Fill field randomly
        this->GenerateField(message, reflection, fd);
    }
}

void RandomGenerator::GenerateField(
    Message * message,
    const Reflection * reflection,
    const FieldDescriptor * fd)
{
109
    // TODO Enums
Giorgio Azzinnaro's avatar
Giorgio Azzinnaro committed
110
111
112
    if (fd->is_repeated()) {
        for (uint k = 0; k < this->RandomValue<google::protobuf::uint32>(); k++) {
            switch (fd->cpp_type()) {
113
114
            #define HANDLE_TYPE(CPPTYPE, METHOD, TYPE)                           \
            case FieldDescriptor::CPPTYPE_##CPPTYPE:                             \
Giorgio Azzinnaro's avatar
Giorgio Azzinnaro committed
115
116
117
118
119
120
121
122
123
124
125
126
127
                reflection->Add##METHOD(message, fd, this->RandomValue<TYPE>()); \
                break;
        
            HANDLE_TYPE(INT32 , Int32 , google::protobuf::int32 );
            HANDLE_TYPE(INT64 , Int64 , google::protobuf::int64 );
            HANDLE_TYPE(UINT32, UInt32, google::protobuf::uint32);
            HANDLE_TYPE(UINT64, UInt64, google::protobuf::uint64);
            HANDLE_TYPE(STRING, String, google::protobuf::string);
            HANDLE_TYPE(DOUBLE, Double, double                  );
            HANDLE_TYPE(FLOAT , Float , float                   );
            HANDLE_TYPE(BOOL  , Bool  , bool                    );
        
            #undef HANDLE_TYPE
128
129
130
            
            case FieldDescriptor::CPPTYPE_MESSAGE:
                this->FillRandomly(reflection->AddMessage(message, fd));
Giorgio Azzinnaro's avatar
Giorgio Azzinnaro committed
131
132
133
134
135
            }
        }
    }
    else {
        switch (fd->cpp_type()) {
136
137
        #define HANDLE_TYPE(CPPTYPE, METHOD, TYPE)                           \
        case FieldDescriptor::CPPTYPE_##CPPTYPE:                             \
Giorgio Azzinnaro's avatar
Giorgio Azzinnaro committed
138
139
140
141
142
143
144
145
146
147
148
149
150
            reflection->Set##METHOD(message, fd, this->RandomValue<TYPE>()); \
            break;
        
        HANDLE_TYPE(INT32 , Int32 , google::protobuf::int32 );
        HANDLE_TYPE(INT64 , Int64 , google::protobuf::int64 );
        HANDLE_TYPE(UINT32, UInt32, google::protobuf::uint32);
        HANDLE_TYPE(UINT64, UInt64, google::protobuf::uint64);
        HANDLE_TYPE(STRING, String, google::protobuf::string);
        HANDLE_TYPE(DOUBLE, Double, double                  );
        HANDLE_TYPE(FLOAT , Float , float                   );
        HANDLE_TYPE(BOOL  , Bool  , bool                    );
        
        #undef HANDLE_TYPE
151
152
153
154
        
        case FieldDescriptor::CPPTYPE_MESSAGE:
            this->FillRandomly(reflection->MutableMessage(message, fd));
            break;
Giorgio Azzinnaro's avatar
Giorgio Azzinnaro committed
155
156
157
158
159
160
        }
    }
}

}
}