From 38a2ce635de89fe2e3686e04b8f146c853c4bfa0 Mon Sep 17 00:00:00 2001 From: Kevin Clark Date: Mon, 25 Aug 2008 21:34:19 +0000 Subject: [PATCH] rb: Speed up Struct#initialize for optional fields [THRFIT-112] Struct#initialize previously walked over every field and checked for default values before assigning nil. The new approach assigns defaults only to fields that have defaults, and lets Ruby handle nil ivars. Author: Bryan Duxbury git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@688891 13f79535-47bb-0310-9956-ffa450edef68 --- lib/rb/lib/thrift/struct.rb | 47 +++++++++++++++++++++++++++++++++---- lib/rb/spec/struct_spec.rb | 3 +-- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/lib/rb/lib/thrift/struct.rb b/lib/rb/lib/thrift/struct.rb index 784fda58..0fbb9e4a 100644 --- a/lib/rb/lib/thrift/struct.rb +++ b/lib/rb/lib/thrift/struct.rb @@ -4,12 +4,51 @@ require 'set' module Thrift module Struct def initialize(d={}) - each_field do |fid, type, name, default| - value = d.delete(name.to_s) { d.delete(name.to_sym) { default.dup rescue default } } - Thrift.check_type(value, struct_fields[fid], name) if Thrift.type_checking + # get a copy of the default values to work on, removing defaults in favor of arguments + fields_with_defaults = fields_with_default_values.dup + d.each_key do |name| + fields_with_defaults.delete(name.to_s) + end + + # assign all the user-specified arguments + d.each do |name, value| + unless name_to_id(name.to_s) + raise Exception, "Unknown key given to #{self.class}.new: #{name}" + end + Thrift.check_type(value, struct_fields[name_to_id(name.to_s)], name) if Thrift.type_checking instance_variable_set("@#{name}", value) end - raise Exception, "Unknown keys given to #{self.class}.new: #{d.keys.join(", ")}" unless d.empty? + + # assign all the default values + fields_with_defaults.each do |name, default_value| + instance_variable_set("@#{name}", (default_value.dup rescue default_value)) + end + end + + def fields_with_default_values + fields_with_default_values = self.class.instance_variable_get("@fields_with_default_values") + unless fields_with_default_values + fields_with_default_values = {} + struct_fields.each do |fid, field_def| + if field_def[:default] + fields_with_default_values[field_def[:name]] = field_def[:default] + end + end + self.class.instance_variable_set("@fields_with_default_values", fields_with_default_values) + end + fields_with_default_values + end + + def name_to_id(name) + names_to_ids = self.class.instance_variable_get("@names_to_ids") + unless names_to_ids + names_to_ids = {} + struct_fields.each do |fid, field_def| + names_to_ids[field_def[:name]] = fid + end + self.class.instance_variable_set("@names_to_ids", names_to_ids) + end + names_to_ids[name] end def struct_fields diff --git a/lib/rb/spec/struct_spec.rb b/lib/rb/spec/struct_spec.rb index 15e84374..8e83d478 100644 --- a/lib/rb/spec/struct_spec.rb +++ b/lib/rb/spec/struct_spec.rb @@ -197,8 +197,7 @@ class ThriftStructSpec < Spec::ExampleGroup end it "should raise an exception when unknown types are given to Thrift::Struct.new" do - lambda { Hello.new(:fish => 'salmon') }.should raise_error(Exception, "Unknown keys given to SpecNamespace::Hello.new: fish") - lambda { Hello.new(:foo => 'bar', :baz => 'blah', :greeting => 'Good day') }.should raise_error(Exception, /^Unknown keys given to SpecNamespace::Hello.new: (foo, baz|baz, foo)$/) + lambda { Hello.new(:fish => 'salmon') }.should raise_error(Exception, "Unknown key given to SpecNamespace::Hello.new: fish") end it "should support `raise Xception, 'message'` for Exception structs" do -- 2.17.1