fixed_key.hpp 7.8 KB
Newer Older
A
arhag 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#pragma once

#include <array>
#include <algorithm>
#include <type_traits>

#include <eosiolib/system.h>

namespace eosio {

15 16 17 18 19
   template<size_t Size>
   class fixed_key;

   template<size_t Size>
   bool operator==(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
A
arhag 已提交
20

21 22
   template<size_t Size>
   bool operator!=(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
A
arhag 已提交
23

24 25 26 27 28
   template<size_t Size>
   bool operator>(const fixed_key<Size> &c1, const fixed_key<Size> &c2);

   template<size_t Size>
   bool operator<(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
A
arhag 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42

    /**
    *  @defgroup fixed_key fixed size key sorted lexicographically
    *  @ingroup types
    * @{
    */
   template<size_t Size>
   class fixed_key {
      private:

         template<bool...> struct bool_pack;
         template<bool... bs>
         using all_true = std::is_same< bool_pack<bs..., true>, bool_pack<true, bs...> >;

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
         template<typename Word, size_t NumWords>
         static void set_from_word_sequence(const std::array<Word, NumWords>& arr, fixed_key<Size>& key)
         {
            auto itr = key._data.begin();
            word_t temp_word = 0;
            const size_t sub_word_shift = 8 * sizeof(Word);
            const size_t num_sub_words = sizeof(word_t) / sizeof(Word);
            auto sub_words_left = num_sub_words;
            for( auto&& w : arr ) {
               if( sub_words_left > 1 ) {
                   temp_word |= static_cast<word_t>(w);
                   temp_word <<= sub_word_shift;
                   --sub_words_left;
                   continue;
               }

               eosio_assert( sub_words_left == 1, "unexpected error in fixed_key constructor" );
               temp_word |= static_cast<word_t>(w);
               sub_words_left = num_sub_words;

               *itr = temp_word;
               temp_word = 0;
               ++itr;
            }
            if( sub_words_left != num_sub_words ) {
               if( sub_words_left > 1 )
                  temp_word <<= 8 * (sub_words_left-1);
               *itr = temp_word;
            }
         }

A
arhag 已提交
74 75 76 77 78 79 80 81 82 83 84 85
      public:

         typedef uint128_t word_t;

         static constexpr size_t num_words() { return (Size + sizeof(word_t) - 1) / sizeof(word_t); }
         static constexpr size_t padded_bytes() { return num_words() * sizeof(word_t) - Size; }

         /**
         * @brief Default constructor to fixed_key object
         *
         * @details Default constructor to fixed_key object which initializes all bytes to zero
         */
A
arhag 已提交
86
         constexpr fixed_key() : _data() {}
A
arhag 已提交
87 88 89 90 91 92 93 94 95 96 97 98

         /**
         * @brief Constructor to fixed_key object from std::array of num_words() words
         *
         * @details Constructor to fixed_key object from std::array of num_words() words
         * @param arr    data
         */
         fixed_key(const std::array<word_t, num_words()>& arr)
         {
           std::copy(arr.begin(), arr.end(), _data.begin());
         }

99 100 101 102 103 104 105 106 107 108 109 110 111
         template<typename Word, size_t NumWords,
                  typename Enable = typename std::enable_if<std::is_integral<Word>::value &&
                                                             !std::is_same<Word, bool>::value &&
                                                             sizeof(Word) < sizeof(word_t)>::type >
         fixed_key(const std::array<Word, NumWords>& arr)
         {
            static_assert( sizeof(word_t) == (sizeof(word_t)/sizeof(Word)) * sizeof(Word),
                           "size of the backing word size is not divisible by the size of the array element" );
            static_assert( sizeof(Word) * NumWords <= Size, "too many words supplied to fixed_key constructor" );

            set_from_word_sequence(arr, *this);
         }

A
arhag 已提交
112 113 114 115 116 117 118 119 120 121 122
         template<typename FirstWord, typename... Rest>
         static
         fixed_key<Size>
         make_from_word_sequence(typename std::enable_if<std::is_integral<FirstWord>::value &&
                                                          !std::is_same<FirstWord, bool>::value &&
                                                          sizeof(FirstWord) <= sizeof(word_t) &&
                                                          all_true<(std::is_same<FirstWord, Rest>::value)...>::value,
                                                         FirstWord>::type first_word,
                                 Rest... rest)
         {
            static_assert( sizeof(word_t) == (sizeof(word_t)/sizeof(FirstWord)) * sizeof(FirstWord),
123 124
                           "size of the backing word size is not divisible by the size of the words supplied as arguments" );
            static_assert( sizeof(FirstWord) * (1 + sizeof...(Rest)) <= Size, "too many words supplied to make_from_word_sequence" );
A
arhag 已提交
125 126

            fixed_key<Size> key;
127
            set_from_word_sequence(std::array<FirstWord, 1+sizeof...(Rest)>{{ first_word, rest... }}, key);
A
arhag 已提交
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
            return key;
         }

         const auto& get_array()const { return _data; }

         auto data() { return _data.data(); }
         auto data()const { return _data.data(); }

         auto size()const { return _data.size(); }

         std::array<uint8_t, Size> extract_as_byte_array()const {
            std::array<uint8_t, Size> arr;

            const size_t num_sub_words = sizeof(word_t);

            auto arr_itr  = arr.begin();
            auto data_itr = _data.begin();

            for( size_t counter = _data.size(); counter > 0; --counter, ++data_itr ) {
               size_t sub_words_left = num_sub_words;

               if( counter == 1 ) { // If last word in _data array...
                  sub_words_left -= padded_bytes();
               }
               auto temp_word = *data_itr;
               for( ; sub_words_left > 0; --sub_words_left ) {
                  *(arr_itr + sub_words_left - 1) = static_cast<uint8_t>(temp_word & 0xFF);
                  temp_word >>= 8;
               }
               arr_itr += num_sub_words;
            }

            return arr;
         }

         // Comparison operators
164
         friend bool operator== <>(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
A
arhag 已提交
165

166
         friend bool operator!= <>(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
A
arhag 已提交
167

168
         friend bool operator> <>(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
A
arhag 已提交
169

170
         friend bool operator< <>(const fixed_key<Size> &c1, const fixed_key<Size> &c2);
A
arhag 已提交
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205

      private:

         std::array<word_t, num_words()> _data;
    };

   /**
    * @brief Compares two fixed_key variables c1 and c2
    *
    * @details Lexicographically compares two fixed_key variables c1 and c2
    * @return if c1 == c2, return true, otherwise false
    */
   template<size_t Size>
   bool operator==(const fixed_key<Size> &c1, const fixed_key<Size> &c2) {
      return c1._data == c2._data;
   }

   /**
    * @brief Compares two fixed_key variables c1 and c2
    *
    * @details Lexicographically compares two fixed_key variables c1 and c2
    * @return if c1 != c2, return true, otherwise false
    */
   template<size_t Size>
   bool operator!=(const fixed_key<Size> &c1, const fixed_key<Size> &c2) {
      return c1._data != c2._data;
   }

   /**
    * @brief Compares two fixed_key variables c1 and c2
    *
    * @details Lexicographically compares two fixed_key variables c1 and c2
    * @return if c1 > c2, return true, otherwise false
    */
   template<size_t Size>
206
   bool operator>(const fixed_key<Size>& c1, const fixed_key<Size>& c2) {
A
arhag 已提交
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
      return c1._data > c2._data;
   }

   /**
    * @brief Compares two fixed_key variables c1 and c2
    *
    * @details Lexicographically compares two fixed_key variables c1 and c2
    * @return if c1 < c2, return true, otherwise false
    */
   template<size_t Size>
   bool operator<(const fixed_key<Size> &c1, const fixed_key<Size> &c2) {
      return c1._data < c2._data;
   }
   /// @} fixed_key

   typedef fixed_key<32> key256;
}