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" <[email protected]>
 *
 * 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"
        "[email protected]#$%^&*()"
        "`~-_=+[{]}\\|;:'\",<.>/? ");
    
    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
        }
    }
}

}
}